I'm using jersey for my rest server, and I got a HTTP 405 error, when I try to forward POST request to relative GET resource.
#Path("/")
public class MyResource {
#POST
#Path("/{method}")
#Produces(MediaType.APPLICATION_JSON)
public String postRequest(#PathParam("method") String method, #Context UriInfo uriInfo, String body) throws IOException {
JsonParser parser = new JsonParser();
JsonObject root = parser.parse(body).getAsJsonObject();
JsonObject params = root;
if (root.has("method")) {
method = root.get("method").getAsString();
params = root.getAsJsonObject("params");
}
UriBuilder forwardUri = uriInfo.getBaseUriBuilder().path(method);
for (Map.Entry<String, JsonElement> kv : params.entrySet()) {
forwardUri.queryParam(kv.getKey(), kv.getValue().getAsString());
}
return new SimpleHttpClient().get(forwardUri.toString());
}
#GET
#Path("/mytest")
#Produces(MediaType.APPLICATION_JSON)
public String getTest(#QueryParam("name") String name) {
return name;
}
}
curl -X POST -d {"method":"mytest","params":{"name":"jack"}} localhost/anythingbutmytest
curl -X GET localhost/mytest?name=jack
These two curl above work fine. But I get a 405 error , when I try to request like this:
curl -X POST -d {"method":"mytest","params":{"name":"jack"}} localhost/mytest
javax.ws.rs.NotAllowedException: HTTP 405 Method Not Allowed
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.getMethodRouter(MethodSelectingRouter.java:466)
at org.glassfish.jersey.server.internal.routing.MethodSelectingRouter.access$000(MethodSelectingRouter.java:94)
......
What should I do?
-------------------------------------Update-------------------------------------
curl -X POST -d {"method":"mytest","params":{"name":"jack"}} localhost/mytest
This curl work fine, when I add a post method like below. But I will write a same POST method for every GET Method like that, is there any other solution?
#POST
#Path("/mytest")
#Produces(MediaType.APPLICATION_JSON)
public String postMyTest(#Context UriInfo uriInfo, String body) throws Exception {
return postRequest(uriInfo.getPath(), uriInfo, body);
}
Besides, is there any other way to re-route POST request to a method in the same class without building a new HTTP request?
You should make
#POST
#Path("/mytest")
and not "getTest" method.Reason is below.
Command
curl -X POST -d {"method":"mytest","params":{"name":"jack"}} localhost/anythingbutmytest
will accept because of
#Path("/{method}") .
But
curl -X POST -d {"method":"mytest","params":{"name":"jack"}} localhost/mytest
will not accept because of
#GET
#Path("/mytest")
POST does not match GET.
Related
I have a java application that calls another application it works well for the exist get function my generate this error 400 BAD_REQUEST when I try to create with a Put function.
curl -XPUT URLSERVER2/users/usernameToBeUsed \
-d '{"password":"passwordToBeUsed"}' \
-H "Content-Type: application/json"
#Service
public class Server2Api {
#Value("${source.server2.base.url}")
private String baseUrl;
Logger log = LoggerFactory.getLogger(getClass());
private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(1);
private final WebClient localApiClient;
public Server2Api(WebClient.Builder localApiClient) {
this.localApiClient = localApiClient.baseUrl(baseUrl).build();
}
public ResponseEntity<Void> creatUser(String username, String pwd){
String body = "{'password':'"+ pwd +"'}";
return localApiClient
.put()
.uri(baseUrl+"/users/"+username )
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(body)
.exchangeToMono(
response -> response.toBodilessEntity()
)
.block(REQUEST_TIMEOUT);
}
}
I just try to change "{'password':'"+ pwd +"'}" to "{password:'"+ pwd +"'}".
with Postman resquest works. URL is ok work on get function
I have this Jersey POST resource :
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response blablabla(InputStream inputStream,
#BeanParam ImportParams importParams) throws IOException, JAXBException, SAXException {
Here is the ImportParams class :
public class ImportParams {
#QueryParam(value = "importType")
public ImportType importType = ImportType.MERGE;
#ApiParam("Force stop point type for all stop points in file. Useful if no modality defined in the netex file.")
#QueryParam(value = "forceStopType")
public StopTypeEnumeration forceStopType;
}
When I use curl to post to the the resource, only the first query parameter I specify after the question mark in the URL is read by jersey :
curl -XPOST -H"Content-Type: application/xml" -H"authorization: bearer $TOKEN" -d#$3 http://localhost:8585/services/stop_places/netex?forceStopType=TRAM_STATION&importType=MERGE
==> forceStopType has the right value, and importType is null
curl -XPOST -H"Content-Type: application/xml" -H"authorization: bearer $TOKEN" -d#$3 http://localhost:8585/services/stop_places/netex?importType=MERGE&forceStopType=TRAM_STATION
==> importType has the right value and forceStopType is null
I've used #BeanParam many times before and it used to work, so I must be missing something obvious.... Thanks for your help
Haha found out - stupid me. Had to put double quotes around the URL when cURLing :
curl -XPOST -H"Content-Type: application/xml" -H"authorization: bearer $TOKEN" -d#$3 "http://localhost:8585/services/stop_places/netex?forceStopType=TRAM_STATION&importType=MERGE"
I work with an Apache Cxf, Spring Jax-rs service and I have the following service definition and the implementations provided,
THE DEFINITION
#POST
#Path("/generateAddress")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON})
WalletInfo generateAddress(final String walletName, String currencyName);
THE IMPLEMENTATIONS
public synchronized WalletInfo generateAddress(final String walletName, String currencyName) {
WalletInfo walletInfo = IWalletInfoDao.getWalletInfoWithWalletNameAndCurrency(walletName, currencyName);
return walletInfo;
}
When I do the POST request with the cURL like
curl -H "Content-Type: application/json" -X POST -d '{"walletName":"Icecream5500","currencyName":"Bitcoin"}' http://localhost:8080/api/rest/wallet/generateAddress
I get the JSON response back,
{
"msg" : "Stream closed",
"date" : "2017-08-28T09:22:027Z"
}
I'm pretty sure that the generateAddress method works fine. What is
the issue here and particularly, when you would get the message Stream closed in the Spring Apache Cxf project while doing the POST requests? Obviously, I can provide more info if required. The server log is normal and I see nothing unusual.
The POST body doesn't match with the parameters of the method and this created the issue in the first place. I have solved the problem in the following options.
I created a new class
public class CreateWalletWithNameAndCurrency {
String walletName;
String currencyName;
public CreateWalletWithNameAndCurrency(String walletName, String currencyName) {
this.walletName = walletName;
this.currencyName = currencyName;
}
public CreateWalletWithNameAndCurrency() {
}
public String getWalletName() {
return walletName;
}
public String getCurrencyName() {
return currencyName;
}
public void setCurrencyName(String currencyName) {
this.currencyName = currencyName;
}
public void setWalletName(String walletName) {
this.walletName = walletName;
}
}
I changed the definition of the POST request like this,
#POST
#Path("generateAddress")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON})
WalletInfo generateAddress(CreateWalletWithNameAndCurrency createWalletWithNameAndCurrency);
The implementation is provided below,
public synchronized WalletInfo generateAddress(CreateWalletWithNameAndCurrency createWalletWithNameAndCurrency) {
String walletName = createWalletWithNameAndCurrency.getWalletName();
String currencyName = createWalletWithNameAndCurrency.getCurrencyName();
WalletInfo walletInfo = iWalletInfoDao.getWalletInfoWithWalletNameAndCurrency(walletName, currencyName);
// some more code
}
Finally, I can do the POST request like this,
curl -H "Content-Type: application/json" -X POST -d '{"walletName":"Copenhangen","currencyName":"Bitcoin"}' http://localhost:8080/rest/wallet/generateAddress
I have the following endpoint declared in my JAX-RS application:
#WebService
public interface AlertWeb
{
#POST
#Path("/add")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public StringResponse addAlert(String name,
int amount, String timespan, String repo, String action);
}
I'm using the following curl command to call this endpoint:
curl -X POST -H "Cache-Control: no-cache"
-H "Content-Type: application/x-www-form-urlencoded"
-d "name=yellow&amount=2×pan=DAY&repo=A&action=%7Baction%3A'GreenDivAction'%2C+message%3A'Simple+Message'%2C+args%3A+%5B'arg1'%2C'arg2'%5D%7D"
http://localhost:8080/AdminService/alert/add
but keep getting the following error when I make the request:
javax.ws.rs.BadRequestException: java.lang.NumberFormatException: For input string: ""
Note Line breaks in curl syntax added for readability.
What am I doing wrong?
You will need to add #FormParam to your method parameters if you want them to be injected as such
#POST
#Path("/add")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response addAlert(
#FormParam("name") String name,
#FormParam("amount") int amount,
#FormParam("timespan") String timespan,
#FormParam("repo") String repo,
#FormParam("action") String action) {
}
I'm trying to gather all parameters of an HTTP POST request into a map, however it's not working.
With a GET, I used:
#Context
private HttpServletRequest request;
and
#GET
#Path("/{uuid}/invoke/{method}")
public Response invokeMethod (
#PathParam("uuid") String uuid,
#PathParam("method") String methodz
) {
Map<String, String[]> params = request.getParameterMap();
and it returned the map. However, when sending form data via a POST instead of inline with the URL, the map is being returned as NULL.
Is there a similar way to retrieve all the parameters at once using a POST?
EDIT:
My data is being submitted as a serialized JSON, so using a cURL statement as an example:
curl --data "firstname=john&lastname=smith" http://localhost:8080/uuid1/apitest/method1
Ideally, I'd want to get a hashmap of something like:
ParamMap["firstname"] = "john"
ParamMap["lastname"] = "smith"
Also, the parameters won't be static, so this cURL:
curl --data "job=construction" http://localhost:8080/uuid2/apitest/method2
would result in:
ParamMap["job"] = "construction"
Finally got this resolved using this thread:
Jersey: Consume all POST data into one object
My new function is:
#POST
#Path("/{uuid}/invoke/{method}")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response invokeMethod (
MultivaluedMap<String,String> params,
#PathParam("uuid") String uuid,
#PathParam("method") String method
) {
Variable 'params' is now a map containing form data key/value pairs.
You can try following code
#POST
#Path("/{uuid}/invoke/{method}")
public Response invokeMethod (
#Context UriInfo request
) {
Map<String, List<String>> params = request.getPathParameters();
}
You no need to write
#Context
private HttpServletRequest request;
Now You can get idea...