Dropwizard sends back 404 Not Found for part of registered endpoints - dropwizard

I have a simple resource which exposes CRUD endpoints.
#Path("/stores/{store-id}/register")
#Produces(MediaType.APPLICATION_JSON)
public class RegisterResource {
#GET
#Path("/{register-id}")
public Response getRegisterById(#PathParam("store-id") Long storeId, #PathParam("register-id") Long registerId) { impl }
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(RegisterDTO registerDto, #PathParam("store-id") Long storeId, #Context UriInfo uriInfo) { impl }
#PUT
#Path("/{register-id}")
#Consumes(MediaType.APPLICATION_JSON)
public Response update(RegisterDTO registerDto, #PathParam("store-id") Long storeId, #PathParam("register-id") Long registerId) { impl }
#DELETE
#Path("/{register-id}")
public Response delete(#PathParam("store-id") Long storeId, #PathParam("register-id") Long registerId) { impl }
}
Dropwizard successfully register my resource:
INFO [2017-03-07 07:03:49,765] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:
POST /stores/{store-id}/register (api.resources.RegisterResource)
DELETE /stores/{store-id}/register/{register-id} (api.resources.RegisterResource)
GET /stores/{store-id}/register/{register-id} (api.resources.RegisterResource)
PUT /stores/{store-id}/register/{register-id} (api.resources.RegisterResource)
Only POST requests are processed. When I send GET/PUT/DELETE request - I receive back 404 Not Found. No exceptions are thrown/logged.
There are also two interesting facts:
1) I have a filter which checks Authorization header. It does not log any requests except POST.
2) I log incoming request int the first statement of every method of my resource. But only requests for POST are logged.
The most interesting fact is that I a day ago and everything was OK. Can't figure out where the problem is... I will appreciate any suggestions what went wrong.

Related

Attribute routing is failing for MVC/WebApi combo project

I am trying to create an ASP.NET app that is both MVC and Web Api. The default controller (HomeController) returns a view that is composed of some HTML and jQuery. I would like to use the jQuery to call the API that is part of the same project.
I have the API setup and have been testing it with Postman but I get the following error when trying to reach the endpoints in the API.
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:19925/api/encryption/encrypt'.",
"MessageDetail": "No action was found on the controller 'Values' that matches the request."
}
I am attempting to use attribute routing so I am pretty sure that is where I am going wrong.
[RoutePrefix("api/encryption")]
public class ValuesController : ApiController
{
[HttpPost]
[Route("encrypt")]
public IHttpActionResult EncryptText(string plainText, string keyPassPhrase)
{
// Method details here
return Ok(cipherText);
}
}
I have the route prefix set to api/encryption. I also have the method using the route encrypt and marked as a HttpPost. Below is my WebApiConfig which I think is configured properly for attribute routing.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
// Default MVC routing
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
By my understanding a POST to the following URL should reach the method ..
http://localhost:19925/api/encryption/encrypt
yet it isn't. I am posting the two string values to the method via Postman. I have attached a screen capture (and yes the keyPassPhrase is fake).
Here is the global.asax as requested ...
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
One other thing to note ... that when I change from GET to POST in Postman it works .. as long as I am sending the parameters along in the query string. If I send the parameters in the body I get the original error.
The problem was that I was trying to POST two values to an API method that accepted two parameters. This is not possible with the API (well not without some work arounds) as the API method is expecting an object rather than two different primitive types (i.e. String).
This means on the server side I needed to create a simple class that held the values I wanted to pass. For example ...
public class EncryptionPayload
{
public string PlainText { get; set; }
public string PassPhrase { get; set; }
}
I then modified my API method to accept a type of this class
[Route("encrypt")]
[HttpPost]
public IHttpActionResult EncryptText(EncryptionPayload payload)
{
string plainText = payload.PlainText;
string passPhrase = payload.PassPhrase
// Do encryption stuff here
return Ok(cipherText);
}
Then inside that controller I pulled the Strings I needed from the EncryptionPayload class instance. On the client side I needed to send my data as a JSON string like this ..
{"plainText":"this is some plain text","passPhrase":"abcdefghijklmnopqrstuvwxyz"}
After changing these things everything worked in Postman. In the end I wasn't taking into account Model Binding, thinking instead that an API endpoint that accepted POST could accept multiple primitive values.
This post from Rick Strahl helped me figure it out. This page from Microsoft on Parameter Binding also explains it by saying At most one parameter is allowed to read from the message body.
Try the following code. It will work :
[RoutePrefix("api/encryption")]
public class ValuesController : ApiController
{
[Route("encrypt"),HttpPost]
public IHttpActionResult EncryptText(string plainText, string keyPassPhrase)
{
// Method details here
return Ok(cipherText);
}
}
Sorry dear it was really compile time error. I edit my code. Please copy it and paste it in yourcode. Mark as answer If i Helped.

Dropwizard UriInfo contain invalid baseUri

I've faced a problem when I get base URI form uriInfo. Here's a part of code:
#Path("/users")
#POST
public Response createUser(#RequestBody User user, #Context UriInfo uriInfo) {
...
String confirmEmailUrl = uriInfo.getBaseUri().resolve("/users/confirm/" + getConfirmEmailLink(user));
...
}
confirmEmailUrl must be like http://XXX.XXX.XXX.XXX:8080/users/confirm/aergserthserg but I get the following result http://XXX.XXX.XXX.XXX/users/confirm/aergserthserg. The problem within the port. I used in some other methods uriInfo to build the URL and it works correctly. What is wrong here?

Grails databinding and allowed HTTP methods

I have the following action in a controller
class RegisterController {
static allowedMethods = [register: 'POST']
def register(User user) {
// action body omitted
}
}
If a user tries to invoke this action via GET /register/register/newUser, I get a databinding failure because newUser cannot be bound to the user's Long id property.
This seems reasonable at first, however IMO no attempt should ever be made to bind the user when it is invoked via HTTP GET, because I've declared that only POST is allowed.
Curiously, if I change the action to:
class RegisterController {
static allowedMethods = [register: 'POST']
def register() {
User user = new User(params)
}
}
and again try to invoke it with GET /register/register/newUser, then I get the expected HTTP method not allowed (405) error. It seems to me that databinding is happening before the HTTP request type is checked, and this is why I get a binding error in the first case and a 405 error in the second.
Shouldn't I get a 405 in both cases?
Yes, you should get a 405 in both cases. File a report at https://jira.grails.org/browse/GRAILS and we will get it straightened out. We have an AST transformation which adds the command object handling code and adds the allowedMethods handling code. It sounds like they may not be in the right order. Will get it straightened out. Thanks for the feedback.

Dart request succeeding ... somehow?

I'm developing a dart application which will consume a REST service I'm building. I started writing out the dart code to perform an ajax request to my login endpoint. However, even when my dart ajax request should fail, it claims to succeed.
I don't have any services up and running (and even if I did it would be using the wrong domain / port right now), but this code gives a 200 OK HttpResponse every time:
class PlayerController {
const PlayerController();
static const String LOGIN_URL = "login";
void login(String username, String password) {
Map<String, String> headers = {"Content-Type": "application/x-www-form-urlencoded"};
String body = "j_username=$username&j_password=$password&submit=Login";
HttpRequest.request(LOGIN_URL, method: "POST", requestHeaders: headers, sendData: body)
.then((request) => processLogin(request, username))
.catchError((e) => processLoginError(e));
}
void processLogin(var whatIsThis, String username) {
query("#loginButton").text = "Logout";
//TODO get the player then set them
}
void processLoginError(var e) {
print("total failure to login because of $e");
}
}
It always hits the processLogin method, and never hits the processLoginError method. Does anyone have any idea why this would be? Should I be performing this ajax request in a different way? (If you couldn't guess, it will be signing into spring security).
I read somewhere that file system requests always succeed. Is Dart somehow making this a file system request rather than a web request?
This is because the request actually completes successfully.
Your request to "login" will actually call http://127.0.0.1:6521/[Path_to_your_Dart_file]/login
The server started by Dart when running in Dartium (127.0.0.1:6521) seems to answer to every POST request with HTTP 200 and an empty response body.
If you change the method from POST to GET, it will fail as expected.
As for why the server does this - I don't really know. This would have to be answered by the Dart team.

FormAuthentication with WebAPI using Breeze

I am protecting WebAPI using forms Authentication, that is using Breezecontroller
When i try to call WebAPi method i am getting back the following error.
status:404
statusText: "Not Found"
message:"MetaData query failed for:'';, No Http resource was found tha matches...
My question is why am i not getting back "UnAuthorized error(401)" ?
metadata is decorated with [Authorize] as well.
Seems like FormsAuthentication's redirect is giving problem.
It is redirecting to Login(has AllowAnonymous) WebApi method and reports it cannot find, eventhough i have. Also i am applying the Authrozie to the methods instead of controller. the exact error is
{"$id":"1","$type":"System.Web.Http.HttpError,System.Web.Http","Message":"NoHTTPresourcewasfoundthatmatchestherequestURI'http://localhost:40678/api/Country/Login?ReturnUrl=/api/Country/Metadata'.","MessageDetail":"Noactionwasfoundonthecontroller'Country'thatmatchestherequest."}
Just tried and working fine. I'm betting you have a mistake in your URL.
Here is the prelim to my controller:
[Authorize]
[BreezeController]
public class BreezeTodoController : ApiController
{
private readonly BreezeTodoContext _context;
public BreezeTodoController() {
_context = new BreezeTodoContext(User);
}
[HttpGet]
public string Metadata() {
return _context.Metadata();
}
// ... more
I hit it with this URL
http://localhost:32377/api/breezetodox/metadata
And I get back the 401
Request URL:http://localhost:32377/api/breezetodo/metadata
Request Method:GET
Status Code:401 Unauthorized
But if I make a mistake in the URL (see 'x' after breezetodo)
Request URL:http://localhost:32377/api/breezetodox/metadata
Request Method:GET
Status Code:404 Not Found
Same thing if my action name doesn't match (see 'x' after metadata):
Request URL:http://localhost:32377/api/breezetodo/metadatax
Request Method:GET
Status Code:404 Not Found
In other words, HTTP can't report that a resource is unauthorized if it can't find that resource in the first place.
when tagging the BreezeController with [Authorize] and then trying to retrieve the Breeze Metadata directly with this link:
Request URL:http://localhost/breeze/breeze/metadata
redirects to:
http://localhost/Login?ReturnUrl=%2Fbreeze%2Fbreeze%2Fmetadata with a 404
Without the [Authorize] the access to the Breeze metadata with the same link works fine.

Resources