I am passing an Employee Object Form Client in RestFul webservices Jaxrs2/jersy2
#GET
#Path("{empObj}")
#Produces(MediaType.APPLICATION_XML)
public Response readPK(#PathParam("empObj")Employee empObj) {
//do Some Work
System.out.println(empObj.getName());
return Response.status(Response.Status.OK).entity(result).build();
}
how can achive this object using GET method??
thanx in advance
By using #PathParam on a method parameter / class field you're basically telling JAX-RS runtime to inject path segment (usually string) to your (String) parameter. If you're sending an object (Employee) representation directly via your URI (query param, path param) you should also provide ParamConverterProvider. Beware that this is not possible in some situation and it's not a recommended practice. However, if you're sending the object from client to server in message body, simply remove #PathParam and MessageBodyReader will take care of converting input stream to your type:
#GET
#Path("{empObj}")
#Produces(MediaType.APPLICATION_XML)
public Response readPK(Employee empObj) {
//do Some Work
System.out.println(empObj.getName());
return Response.status(Response.Status.OK).entity(result).build();
}
Related
Epicor ERP 10.2.500 has been recently released with the addition of Epicor Functions. They can be called from within Method and Data Directives.
Do anybody has been able to do so with a Form Customization within Epicor?
This is possible via a REST call to your function API. In this case, I had a function that sent an email from some inputs.
private void epiButtonC1_Click(object sender, System.EventArgs args)
{
//API Key is included in the query param in this example.
var request = (HttpWebRequest)WebRequest.Create("https://{appserver}/{EpicorInstance}/api/v2/efx/{CompanyID}/{LibraryID}/{functionName}/?api-key={yourAPIKey}");
request.Method = "POST";
//All REST v2 requests also sent with authentication method (Token, Basic)
//This should be Base64 encoded
string username = "userName";
string password = "passWord";
string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
request.Headers.Add("Authorization", "Basic " + encoded);
//Add body to correspond to request signature
request.ContentType = "application/json";
using(var writer = new StreamWriter(request.GetRequestStream()))
{
var values = new Dictionary<string, string>;
{
{"toEmailAddress", "someEmail#email.com"},
{"fromEmailAddress","someOtherEmail#email.com"},
{"body","This is the body"},
{"subject","Hello from Client Code!"}
};
string json = JsonConvert.SerializeObject(values);
writer.Write(json);
}
using (var response = request.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
var result = reader.ReadToEnd();
epiTextBoxC1.Text = result.ToString();
}
}
Haven't done it myself personally, but looking into the first post release notes about it here leads me to believe there is no out of the box solution, yet in this version/initial release.
However I'm sure you could do a HTTP request from within the Epicor customization if you have the REST API enabled in your environment.
If you create your own dll that calls the EpicorFunction you can use it within the customization. Still looking for a way to call them directly.
REST endpoint is the recommended way to perform the function call as pointed out by a-moreng.
If for some reason you cannot use this, you can use a passthrough method to any server-side BO via a customization Adapter. For instance, create an updatable BAQ which you can call from a customization using the DynamicQueryAdapter.
Pick an arbitrary table and field to save the BAQ.
Create three string parameters to store the Function library name, the function name, and a delimited list of parameters.
On the GetList method, create a Base Processing Directive.
Split your delimited parameter list and convert them to the appropriate datatypes.
Use the resulting variables to call your function.
If desired, you can pass return variables into the ttResults of the BAQ
The required URL should be something like this :
http://<host>:<port>/path/item?<arguments>
The arguments key and value supposed to be multiple and dynamic, so I cannot use #BeanParam or #QueryParam. Also I can only call this interface without implementation.
My current code is something like this :
public interface RestService {
#GET
#Path("/path/item")
#Produces(MediaType.APPLICATION_JSON)
public JsonNode method(#QueryParam("params") String params);
}
Example of arguments that I want to pass : brand=myBrand&price=myPrice
Is there any way to do something like this ?
My References :
REST Web Service - Dynamic Query Parameters
Passing indefinite Query Parameters with RESTful URL and reading them in RESTEasy
Use UriInfo.getQueryParameters(), as following:
#GET
#Path("/path/item")
#Produces(MediaType.APPLICATION_JSON)
public JsonNode method(#Context UriInfo uriInfo) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
...
}
It returns a MultivaluedMap. Then just iterate over it.
TLDR: Multiple Pathparameters and Endpoints with Swagger
What i would like to to is some API Endpoint like this:
/foo/{id}/bar
Now afaik foo or the first node in the path is defining the endpoint and also the resource to aqcuire. Therefore a FooApiServiceImpl is generated.
The generated ProjectsApiService stub looks like this atm:
#GET
#Path("/{id}/bars")
...
public Response getBarsByFooId(#ApiParam(value = "The id of the foo with the bars",required=true ) #PathParam("id") String id)
throws NotFoundException {
return delegate.getBarByFooId(id);
}
Now my wished behaviour would be to GET all the Bar resources that are connectted to the Foo with the given {id}. Kinda like the reverse order. Is this somehow possible?
If this is not possible... then would also like to ask, how can i get url nodes (foo, bar) that are not defined as {xxx} paramaters in brackets?
Something like this:
public Response getBarsByFooId(String foo, String id, String bar)
throws NotFoundException {
return delegate.getBarByFooId(id);
}
To get the paths segments, inject a UriInfo in your resource class or method:
#Context
private UriInfo uriInfo;
And then invoke UriInfo.getPathSegments() from it:
List<PathSegment> segments = uriInfo.getPathSegments();
See the UriInfo.getPathSegments() documentation:
Get the path of the current request relative to the base URI as a list of PathSegment. This method is useful when the path needs to be parsed, particularly when matrix parameters may be present in the path. All sequences of escaped octets in path segments and matrix parameter values are decoded, equivalent to getPathSegments(true).
I am using play 2.2.2. I have apis of the form
/users?token=abcd
/users?resetToken=abcd
I have configured my route as follows:
GET /users controllers.X.method(token: String)
GET /users controllers.Y.method(resetToken: String)
Now, when I make a call to the /users?resetToken=tokenvalue, I get the following error
For request 'GET /users?resetToken=tokenvalue' [Missing parameter: token]
I could have solved this by routing both the apis to the same method and then checking the query params inside the method. But I want to route the apis to two different methods because of the access restrictions on each of them. One of the apis can be accessed only after login while the other can be accessed with/without login.
Could you please help me resolve the issue?
(Adding more information:)
I tried the following:
GET /users controllers.A.genericMethod()
GET /usersByToken/:token controllers.X.method(token: String)
GET /usersByResetToken/:token controllers.Y.method(token: String)
In controllers.A,
public static Promise<Result> genericMethod(){
Map<String, String[]> queryParams = Context.current().request().queryString();
String[] tokens = queryParams.get("token");
String[] resetTokens = queryParams.get("resetToken");
if (tokens != null && tokens.length == 1) {
return Promise.pure((Result) redirect(controllers.routes.X.method(tokens[0])));
} else if (resetTokens != null && resetTokens.length == 1) {
return Promise.pure((Result) redirect(controllers.routes.Y.method(resetTokens[0])));
} else {
ObjectNode node = ControllerHelper.error(ResponseStatus.BAD_REQUEST,
"Required params not set!");
return Promise.pure((Result) badRequest(node));
}
}
In controllers.X
#SubjectPresent
public static Promise<Result> method(){
....
}
In controllers.Y
public static Promise<Result> method(){
....
}
This works from the play framework point of view.
But I am calling these apis from ember framework through ember-data. So, if I make a call to it from ember-data, say using
this.store.find('user', {token: "abcd"});
which forms the corresponding api url
/users?token=abcd
I get a response of "303, see other" and the required data is not returned.
You can't declare two routes with the same method and path, fortunately you don't have to, you have two solutions, first is declaring 'Optional parameters' (#see: doc) like
GET /users controllers.X.action(token ?= null, resetToken ?= null)
public static Result action(String token, String resetToken){
if (token==null) debug("No token given...");
// etc
}
Other solution is declaring rout w/out params, as you can still get arguments with DynamicForm
GET /users controllers.X.action()
public static Result action(){
DynamicForm dynamicForm = Form.form().bindFromRequest();
String token = dynamicForm.get("token");
if (token==null) debug("No token given...");
// etc
}
Second approach is better especially if your API has large amount of optional params.
Note: Written from top of my head
I understand that one api is protected, requiring a login, and another does not.
You need to have two separate routes, this is the best way.
GET /users controllers.X.method(token: String)
GET /public/users controllers.Y.method(resetToken: String)
Combining it into one route will not allow you to have separate access restrictions.
You need to break it into two routes, one with a private access and one with a public access.
This will change your apis obviously.
i'm having problems transfering a custom object to the client. How can i transfer a custom object to the client and receive it back to the webservice? i'm transferring a file by chunks. i want to know how i should write my client. i tried passing it as MediaType.APPLICATION_JSON in client but i get no result meaning it doesn't get passed back to the webservice. Below is a bit of code im working on.
Webservice
#POST
#Path("/fileTransfer")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public final TransferInfomation transferInfo(final FileModel file)
{
...
}
...(some code)(lets just say a syso)
FileModel Class
public class FileModel {
private String fileID;
private DataHandler dataHandler;
/**
* Constructor.
*/
public FileModel() {
}
(lets assume setters and getters are made)
(Not sure if the webservice is correct). Still learning REST, i want to know how the client should be.
thanks in advance.
A good way to "marshal" and "unmarshal" "custom objects" (in JSON, XML, etc.) in Jersey is to use JAXB (https://jaxb.java.net/).
To do this you need to create a "jaxb class", with the proper getters and setters (and annotations), e.g.:
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class FileModel{
private String fileID;
private DataHandler dataHandler;
public String getFileID(){
return fileID;
}
public void setFileID(String fileID){
this.fileID = fileID;
}
public DataHandler getDataHandler(){
return dataHandler;
}
public void setDataHandler(DataHandler dataHandler){
this.dataHandler = dataHandler;
}
}
Do not forget to declare the #XmlRootElement. Then you can simply declare and use these objects in your API endpoints (methods):
#POST
#Path("/fileTransfer")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public final FileModel transferInfo(FileModel file)
{
// read file in "FileModel" format
// ... make several operations
// return new FileModel (or another format if you will)
}
This should work. Make sure you follow the data structure defined for FileModel correctly in the client side. See here a example on how to handle that in Jersey: How do I POST a Pojo with Jersey Client without manually convert to JSON? (where JAXB is also used).
Your REST endpoint indicates you want to consume and produce JSON. So the REST client needs to send JSON that can be deserialized into FileModel, and the TransferInfomation returned by transferInfo needs to be serialized into JSON to return to the client.
Typically, Java REST frameworks like RESTEasy, Restlet, Camel, and Spring MVC provide facilities that let you define a JSON serializer/deserializer like Jackson and the mapping rules from JSON <--> Java, and the framework handles the details for you.
So if you use one of these frameworks, you will just have to configure them to use the preferred JSON tool and define the rules.
You can achive this like below:
Server Side:
#PUT
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public String addRecord(CustomClass mCustomClass)
{
///
///
///
return "Added successfully : "+CustomClass.getName();
}// addRecord
Client Side:
public static void main(String[] args)
{
///
///
///
CustomClass mCustomClass = new CustomClass();
Client client = ClientBuilder.newClient();
String strResult = client.target(REST_SERVICE_URL).request(MediaType.APPLICATION_XML).put(Entity.xml(mCustomClass), String.class);
}