I want to specify a query param in Router Function with Spring 5 web reactive. Here my example:
/api/cars?model={model}
but when I replace the query param by a value, it is route to the url :
/api/cars
and not the one with the query param.
In fact, I have found the solution few months ago. I post the code maybe it will helps. Here my example
#Bean
public RouterFunction<ServerResponse> routerFunction() {
return route(GET("/cars"), carHandler::handleFindAll)
.and(route(GET("/cars?model={model}"), carHandler::handleFindAll));
// no need tho specify the request param into the route
}
Here my handler
public Mono<ServerResponse> handleFindAll(ServerRequest request) {
request.queryParam("model"); // will contains the request param ?cars/model=Audi
return ServerResponse.ok().body(initCars(), Car.class);
}
and how we manage find all and find all with request param
Related
**web-api**
As u can see I have to develop different api . For this I have created a MasterController. But I am getting an problem. I am using Postman for testing and I am getting the following problem. Please help me to resolve this issue. I am getting multiple match points. Please help me resolve the issue.
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VENUS.HRMS.API.Filters;
using VENUS.HRMS.DATA.Data;
using VENUS.HRMS.DATA.Models;
namespace VENUS.HRMS.API.Controllers
{
[ApiController]
[Route("[controller]")]
public class MasterController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpGet]
[AuthorizationFilter]
public IEnumerable<TblMstEmpRole> Get()
{
var emprole = new EmpRoleData().GetMstEmpRole();
return emprole;
}
[HttpGet]
[AuthorizationFilter]
public IEnumerable<TblMstState> GetState()
{
var state = new StateData().GetMstState();
return state;
}
[HttpGet]
[AuthorizationFilter]
public IEnumerable<TblMstCity> GetCity()
{
var city = new CityData().GetMstCity();
return city;
}
}
}
The issue is exactly what error says: The request matched multiple endpoints
Remember when calling an API, the function name does not matter. The function name is only for "Internal" use within your C# applicaiton. The name of the API endpoint correlates to it's route. This route is set with either the [Route()] attribute or within the [HttpGet()] attribute.
For example you have 3 functions:
[HttpGet]
public IEnumerable<TblMstEmpRole> Get()
[HttpGet]
public IEnumerable<TblMstState> GetState()
[HttpGet]
public IEnumerable<TblMstCity> GetCity()
The full route for these three functions respectively are:
Get --> /Master/
Get --> /Master/
Get --> /Master/
Yes all thee are the same. And that is the exact issue you are having. To fix this change the Route for your endpoints like this:
[HttpGet]
public IEnumerable<TblMstEmpRole> Get()
[HttpGet("State")]
public IEnumerable<TblMstState> GetState()
[HttpGet("City")]
public IEnumerable<TblMstCity> GetCity()
Now the routes will look like this:
Get --> /Master/
Get --> /Master/State
Get --> /Master/City
The rule is:
You can only have one route name per Http operation.
Different HTTP Methods
[HttpGet] is one of the attributes which has a GET method, however, there are many other methods such as POST, HEAD, PUT, OPTIONS, DELETE, CONNECT, TRACE and PATCH.
To utilize them through an API endpoint all you need to do is add it to the function. All the attributes have the [Http***] format. Example Post and Put will be:
[HttpPost]
[HttoPut]
And has mentioned a little above, you can only have one Route for each method. See examples below:
// PATH: GET --> /Master/
[HttpGet]
public IEnumerable<TblMstEmpRole> GETGet()
// PATH: POST --> /Master/
[HttpPost]
public IEnumerable<TblMstEmpRole> POSTGet()
The above example is VALID. Even though we have two functions with the same route, they do have different Http Methods and as such are uniquely identifiable.
Why Different Methods
Each method has it's own quirks and uses. Depending on the method, some things are allowed and some are not. When a client makes a query to a server and sends something, that is called a Http Request. The method for either getting or setting it is the Http Method, example GET, POST, PUT...
A Http Request has the following structure:
Headers
Parameters
Body
Footer
If we were to use the GET method, then you are telling the endpoint that it should ignore the Body of the request.
If we were to use the HEAD method then we are telling the endpoint that we are only interested in the Headers section of the request.
Now to figure out which to use and when can be tricky, but as a basic rule of thumb you can use this:
GET - You are only fetching data and not sending anything in the body
POST - When you are creating something in the database or sending data in the body
PUT - Similar to Post, but only when you are updating something
DELETE - When you are removing something.
These are the basic 4 any beginner to intermediate should be aware of. For more information on what method to use see: https://www.w3schools.com/tags/ref_httpmethods.asp
I am trying to figure out how to add query parameters to a route when using RouterFunctions. Here's what I have so far:
#Bean
public RouterFunction<ServerResponse> routes() {
return
RouterFunctions.route()
.GET("/one/{one}", routeHandlerOne::handlerOne)
.GET("/two", routeHandlerOne::handlerTwo)
.build();
}
For route two I want add a query parameter, like /two?three. Any help would be most helpful, thank you!
There is a queryParam() method on the RequestPredicates class you can use.
RouterFunctions.route()
.GET("/one", RequestPredicates.queryParam("test", t -> true), new CustomHanlder())
.build();
There are two overloaded methods for queryParam(). One takes the exact value to compare against (javadoc). The second (the one in the example above) takes a predicate and will delegate to the handler function if the predicate returns true (javadoc).
You can then access the query params through the ServerRequest object in your handler function ie.
serverRequest.queryParam("test")
If you want multiple query parameters then you can do it this way
.GET("/login", RequestPredicates.all()
.and(queryParam("username", t -> true))
.and(queryParam("password", t -> true)), handler::login)
I have developed Small Spring boot Rest api app. I can able to get the data or create new record and search with paging and sorting.
Now i'm looking for provide input data in body to get the data instead of providing in URL with GET method. Is this method also default function ? Please advise.
public interface CodeTextRepository extends PagingAndSortingRepository<CodeText, Long> {
}
How to write POST method to just get the data ?
http://localhost:8080/api/code
method : POST
{
"code":1
}
If I understand you correctly, you want to create a controller that will get the a model as body parameter ({ "code": 1 }) in a POST method and then do something with it.
To do that, you can create a controller that looks like the following (I inserted pseudo-code as an example):
#RestController
#RequestMapping(value = "/api/code")
public class CodeTextController {
private CodeTextRepository codeTextRepository;
// constructor injection
public CodeTextController(CodeTextRepository codeTextRepository) {
this.codeTextRepository = codeTextRepository;
}
#PostMapping
public CodeText postCodeText(#RequestBody CodeTextRequest codeTextRequest) {
// some code to get from the DB
return codeText;
}
}
public class CodeTextRequest {
private int code;
// getters and setters
}
Simply add Accept header to the request, like
accept: application/json
Spring Data-Rest will return the body after a POST request if either the returnBodyOnCreate flag was explicitly set to true in the RepositoryRestConfiguration OR if the flag was NOT set AND the request has an Accept header.
You can set the flag directly during configuration, or you can set it via the application.properties:
spring.data.rest.returnBodyOnCreate = true
you can also set it separately for update:
spring.data.rest.returnBodyOnUpdate = true
---- edit
Maybe I misunderstood your question. If you simply want to GET an existing data using POST method, then DO NOT DO IT AT ALL! That's not a REST API any more. There must be some reason you want to do it, but you should try do resolve that original problem instead in another way!
Here is the controller:
Here is the postman:
Via form-data, I can get caseId in my controller.
But raw with header, I can't.
I don't know why... Is there anything wrong with my controller ?
Please help, thanks.
edit 1:
Yeah. Add something more
We know, springMVC will bind data for us, but when we use POST request and put data in body via raw and Content-Type:application/json, spring will still bind data? request.getInputStream() will only call once.
edit 2:
I found a way to get the raw.
get the json string.
edit in 11/29/2017
I found that:
Post with raw, I need to use #RequestBody to recive the value.
Here are the example of how to retrieve data using POSTMAN and bind with SpringMVC
#RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.findAllUsers();
if (users.isEmpty()) {
return new ResponseEntity(HttpStatus.NO_CONTENT);
// You many decide to return HttpStatus.NOT_FOUND
}
return new ResponseEntity<List<User>>(users, HttpStatus.OK);
}
You may refer to this article : Spring Boot Rest API Example
Can u bind request param as below and check :
public Object getTcaseByCaseId(#RequestParam("caseId") String caseId) {
Hi every one I am new to Asp.net Web API and I had my question post data using asp.net Web API and got my answer accepted.
This is an extension to the same question I want to post data with some header value in the Postman and my code is as follows
public HttpResponseMessage PostCustomer([FromBody] NewUser userData, string devideId)
{
//My code
return response;
}
When I hit this in Postman passing values in JSON format in BODY - raw I got message as follows
No HTTP resource was found that matches the request URI
No action was found on the controller that matches the request.
Please help me.
It looks like you have added some additional devideId string parameter to your action. Make sure that you are supplying a value to it as a query string when making the request:
POST http://localhost:58626/api/customers?devideId=foo_bar
If you don't want to make this parameter required then you should make it optional (in terms of optional method parameter in .NET):
public HttpResponseMessage PostCustomer([FromBody] NewUser userData, string devideId = null)
{
...
}
Now you can POST to http://localhost:58626/api/customers without providing a value for this parameter.
Remark: You don't need to decorate a complex object type (such as NewUser) with the [FromBody] attribute. That's the default behavior in Web API.
UPDATE: Here's how you could read a custom header:
public HttpResponseMessage PostCustomer(NewUser userData)
{
IEnumerable<string> values;
if (this.Request.Headers.TryGetValues("X-MyHeader", out values))
{
string headerValue = values.FirstOrDefault();
}
...
return response;
}