How to send a success/failure message in json in web api? - json

How to send a success/failure response in json after execution of the webapi action?I have a function called FundTransfer, how to implement it like the output: given below
FundTransfer(string FromAccountNo, string ToAccountNo, decimal Amount,
string Remarks)
Output:
return: Success OR Fail with reason
string MsgCode: 00 (means success) OR 11 (means failure)
string Message: "Insufficient Balance ... or any other reason" (if fail,
there must be some reason in the Message")
At the moment when i call the api it executes and sends true on successfull execution
My Webapi Action (Now)
[HttpPost]
[ActionName("transfer")]
public IHttpActionResult FundTransfer([FromBody] FundTransfer transfer)
{
var transferData = BusinessLayer.Api.AccountHolderApi
.FundTransfer(transfer);
return Ok(transferData);
}
Business Layer
public static bool FundTransfer(FundTransfer transferData)
{
return
DatabaseLayer.Api.AccountHolderApi.FundTransfer(transferData);
}
DatabaseLayer
public static bool FundTransfer(FundTransfer transferData)
{
string sql = #"SELECT * FROM sms.post_fund_transfer('" +
transferData.FromAccount + "','" +
transferData.ToAccount + "','" + transferData.Amount +
"','" + transferData.Statement + "')";
using (var command = new NpgsqlCommand(sql))
{
return DBOperations.ExecuteNonQuery(command);
}
}
I am still learning webapi and did find some questions/answers related to response messages but couldnt get through.any help appreciated.
Thank You.

You could create a class which holds the response data type
public class responseMsg
{
public class MsgCode { get; set; }
public class Message { get; set; }
}
Then use that in your FundTransfer method
public responseMsg FundTransfer(string FromAccountNo, string ToAccountNo, decimal Amount, string Remarks)
{
//implement logic and create a response
return new responseMsg { MsgCode = "11", Message="Insufficient Balance ..." };
}
Then read the MsgCode in the api method and set the http response code
[HttpPost]
[ActionName("transfer")]
public IHttpActionResult FundTransfer([FromBody] FundTransfer transfer)
{
//call your logic which response with the responseMsg
var response = logic();
if(response.MsgCode == "11")
{
return Content(HttpStatusCode.BadRequest, response.Message);
}
else
{
return Ok(response.Message);
}
}

Related

How to set JWT type in JWT Header

Not able to set the JWT token typ in token header.
This is for making secure API's which i have already developed in JAX-RS. Basically i have generating a token by Jwts.builder() method, and in return i am getting token in APPLICATION_JSON, ant i paste this token at https://jwt.io/ Debugger. So i got to know that there is no token type specified token header,there is only {
"alg": "HS512"
}
Maybe this could be a reason that i cannot access secured API's. When i try to access secured API's then i got "Signed Claims JWSs are not supported" exception.
AuthenticationService.java
private String issueToken(String login, String password) {
LocalDateTime now = LocalDateTime.now().plusMinutes(10L);
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
Date jwtExpiry = Date.from(instant);
String jwtToken = Jwts.builder().setSubject(login).setIssuer("XYZ").setIssuedAt(new Date())
.setExpiration(jwtExpiry).signWith(SignatureAlgorithm.HS512, "secretKey").compact();
return jwtToken;
}
public class JWTTokenNeededFilter implements ContainerRequestFilter
{
public static final Logger logger = Logger.getLogger(JWTTokenNeededFilter.class);
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
String token = requestContext.getHeaderString("userToken");
if (token == null) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
try {
Jwts.parser().setSigningKey("secretKey").parseClaimsJwt(token);
logger.info("Valid Token " + token);
} catch (ExpiredJwtException expiredJwtException) {
logger.info("Token Expires " + expiredJwtException);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
catch (Exception exception) {
logger.info("Exceptioin " + exception);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
}
I am expecting token header like this
{
"alg": "HS512",
"typ": "JWT"
}
You can set the header just using the setHeaderParam("typ","JWT") jwt builder method.
https://github.com/jwtk/jjwt#header-parameters
String token = Jwts.builder()
.setHeaderParam("typ","JWT")
.setSubject(user.getUserId().toString())
.claim("Roles",authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()+EXPIRATION_TIME))
.signWith(Keys.hmacShaKeyFor(key))
.compact();
You can set using header as explained here : https://github.com/jwtk/jjwt/issues/174
Header header = Jwts.header();
header.setType("JWT");
Then set header to builder (I haven't compiled the code)
private String issueToken(String login, String password) {
LocalDateTime now = LocalDateTime.now().plusMinutes(10L);
Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
Date jwtExpiry = Date.from(instant);
Header header = Jwts.header();
header.setType("JWT");
//set additional headers
String jwtToken =
Jwts.builder().setHeader((Map<String, Object>)
header).setSubject(login).setIssuer("XYZ").setIssuedAt(new
Date())
.setExpiration(jwtExpiry).signWith(SignatureAlgorithm.HS512,
"secretKey").compact();
return jwtToken;
}
you can use Header.JWT_TYPE static field in Header interface. This is more cleanable and avoid boilerplate code: For example:
private static String generateToken() {
return Jwts.builder()
.signWith(SignatureAlgorithm.HS256, secretKey)
.setHeaderParam("typ", Header.JWT_TYPE)
.compact();
}
and output which you want:
{
"typ": "JWT",
"alg": "HS256"
}

Get data array from sqlite database and post to API via json object... can be possible?

newbie here... i was developing app that send my data to api via retrofit. my code was working but it sends 1 data input only at the time.... in my case, i've like to do is I want to get more saved data in my sqlite (example 5 data saved) and send it all on api via json object.
This is my Activity:
DatabaseHelper databaseHelper2 = new
DatabaseHelper(getApplicationContext());
SQLiteDatabase db2 =
databaseHelper2.getWritableDatabase();
Cursor cursor =
databaseHelper2.retrieveSettingFromLocalDatabase(db2);
while (cursor.moveToNext()) {
ADDRESS =
cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_ADDRESS));
PORT =
cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_PORT));
TIMEINTERVAL=cursor.getString
(cursor.getColumnIndex(DatabaseHelper.SETTING_TIME_INTERVAL));
}
portInts=Integer.parseInt(PORT);
MapDetails mapDetails = new MapDetails(gg, lat, lon,
well, "0", portInts); //Datas ive get to send in api
List<MapDetails> data = new ArrayList<>();
data.add(mapDetails);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + ADDRESS + ":" + PORT)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
Api locate = retrofit.create(Api.class);
Call<MapDetails> call = locate.mapDetailLocation(data);
call.enqueue(new Callback<MapDetails>() {
#Override
public void onResponse(Call<MapDetails> call, Response<MapDetails> response) {
Snackbar.make(view, "" + response,
Snackbar.LENGTH_INDEFINITE)
.setAction("Action", null).show();
}
#Override
public void onFailure(Call call, Throwable t) {
Snackbar.make(view, "" + t.getMessage(),
Snackbar.LENGTH_INDEFINITE)
.setAction("Action", null).show();
}
});
This is my code in API:
public interface Api {
#POST("/api/Database/NewLocation")
Call<MapDetails> mapDetailLocation(#Body List<MapDetails> mapDetails)
}
This is my sample Client:
public class MapDetails {
#SerializedName("SerialNumber")
#Expose
private String SerialNumber;
#SerializedName("Coordinate1")
#Expose
private String Coordinate1;
#SerializedName("Coordinate2")
#Expose
private String Coordinate2;
#SerializedName("DateTime")
#Expose
private String DateTime;
#SerializedName("Speed")
#Expose
private String Speed;
#SerializedName("Port")
#Expose
private int Port;
public MapDetails(String serialNumber, String coordinate1, String
coordinate2, String dateTime, String speed, int port) {
SerialNumber = serialNumber;
Coordinate1 = coordinate1;
Coordinate2 = coordinate2;
DateTime = dateTime;
Speed = speed;
Port = port;
}
public String getSerialNumber() {
return SerialNumber;
}
public void setSerialNumber(String serialNumber) {
SerialNumber = serialNumber;
}
public String getCoordinate1() {
return Coordinate1;
}
public void setCoordinate1(String coordinate1) {
Coordinate1 = coordinate1;
}
public String getCoordinate2() {
return Coordinate2;
}
public void setCoordinate2(String coordinate2) {
Coordinate2 = coordinate2;
}
public String getDateTime() {
return DateTime;
}
public void setDateTime(String dateTime) {
DateTime = dateTime;
}
public String getSpeed() {
return Speed;
}
public void setSpeed(String speed) {
Speed = speed;
}
public int getPort() {
return Port;
}
public void setPort(int port) {
Port = port;
}
}
this is my sqlite database ive like to retrieve:
this is the sample posting ive created at the top
but in my case, ive like to do is this one, getting the saved data from my database and send it like this,:
The reason why only one is being sent is that you are sending outside of the while loop that traverses the Cursor, so only the last is sent.
That is you have :-
while (cursor.moveToNext()) {
ADDRESS = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_ADDRESS));
PORT = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_PORT));
TIMEINTERVAL=cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_TIME_INTERVAL));
}
So say the query extracted a Cursor with 10 rows as address 1,2,3....10 (for explantory purposes) then
The loop is entered ADDRESS is set to 1, the next iteration sets it to 2, the next to 3 ..... and finally ADDRESS is set to 10 (same for PORT and TIMEINTERVAL)
After the loop the data is sent so only one is sent (ADDRESS 10).
What you need is along the lines of :-
List<MapDetails> data = new ArrayList<>();
MapDetails mapDetails
Retrofit.Builder builder;
Retrofit retrofit;
Call<MapDetails> call;
Api locate;
while (cursor.moveToNext()) {
ADDRESS = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_ADDRESS));
PORT = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_PORT));
TIMEINTERVAL=cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_TIME_INTERVAL));
portInts=Integer.parseInt(PORT);
mapDetails = new MapDetails(gg, lat, lon, well, "0", portInts);
data.clear(); //<<<<<<<< remove previous entries if required????
data.add(mapDetails);
builder = new Retrofit.Builder()
.baseUrl("http://" + ADDRESS + ":" + PORT)
.addConverterFactory(GsonConverterFactory.create());
retrofit = builder.build();
locate = retrofit.create(Api.class);
call = locate.mapDetailLocation(data);
call.enqueue(new Callback<MapDetails>() {
#Override
public void onResponse(Call<MapDetails> call, Response<MapDetails> response) {
Snackbar.make(view, "" + response,
Snackbar.LENGTH_INDEFINITE).setAction("Action", null).show();
}
#Override
public void onFailure(Call call, Throwable t) {
Snackbar.make(view, "" + t.getMessage(),
Snackbar.LENGTH_INDEFINITE).setAction("Action", null).show();
}
}
Note the above is in-principle code. it has not been checked or tested and may therefore contain some errors.
It may be that you can send an entire set e.g. data with populated in which case you may only need up to data.add(mapDetails); in the loop and then have the following code outside the loop.
If I understood your question properly, you need to send JSONArray as payload for the request. But, you made a little mistake while preparing payload from SQLite database. #Mike T pointed out that mistake in his answer to your question.
Follow these codes to fix the problem.
DatabaseHelper databaseHelper2 = new DatabaseHelper(getApplicationContext());
SQLiteDatabase db2 = databaseHelper2.getWritableDatabase();
Cursor cursor = databaseHelper2.retrieveSettingFromLocalDatabase(db2);
List<MapDetails> data = new ArrayList<>(); // declare ArrayList outside and before while loop
while (cursor.moveToNext()) {
ADDRESS = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_ADDRESS));
PORT = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_PORT));
TIMEINTERVAL = cursor.getString(cursor.getColumnIndex(DatabaseHelper.SETTING_TIME_INTERVAL));
// pass arguments to MapDetails class constructor
portInts = Integer.parseInt(PORT);
MapDetails mapDetails = new MapDetails(gg, lat, lon, well, "0", portInts); //Datas ive get to send in api
// add prepared data to ArrayList
data.add(mapDetails);
}
// and finally execute network call
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + ADDRESS + ":" + PORT)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
Api locate = retrofit.create(Api.class);
Call<MapDetails> call = locate.mapDetailLocation(data);
call.enqueue(new Callback<MapDetails>() {
#Override
public void onResponse(Call<MapDetails> call, Response<MapDetails> response) {
Snackbar.make(view, "" + response, Snackbar.LENGTH_INDEFINITE).setAction("Action", null).show();
}
#Override
public void onFailure(Call call, Throwable t) {
Snackbar.make(view, "" + t.getMessage(), Snackbar.LENGTH_INDEFINITE).setAction("Action", null).show();
}
});
PS: I'm not sure why are you taking ADDRESS and PORT from SQLite database. If they're same in every single row you don't need to take it from database right?

mock.method call returns null after stubbing

I am trying to test using Mockito
my class under test is
#Service
public class DynatraceAPIServiceImpl implements DynatraceAPIService {
private String apiUrl = "someurl";
private String apiToken = "sometoken";
#Override
public CreateCustomMetricResponse createCustomMetric(CreateCustomMetricRequest request) throws MonitoringException {
logger.info("Inside create custom metric");
if (request == null) {
logger.error("create metric request is null");
throw new MonitoringException("Create metric request is null");
}
String metricId = DynatraceConstants.METRIC_ID;
String displayName = request.getDisplayName();
CreateCustomMetricResponse response = httpUtils.postCustomMetric(apiUrl + "/v1/timeseries/" + metricId, apiToken, request);
if (response == null) {
logger.error("Error in creating custom metric with name : " + displayName);
throw new MonitoringException("Error in creating custom metric with name : " + displayName);
}
logger.info("Custom metric : " + displayName + " is created successfully.");
return response;
}
}
and my Test class is :
#RunWith(MockitoJUnitRunner.class)
public class DynatraceAPIServiceImplTest {
#InjectMocks
DynatraceAPIServiceImpl dynatraceAPIServiceImpl;
#Mock
DynatraceHttpUtils httpUtilsMock;
#Mock
DynatraceMonitoringUtils monitoringUtilsMock;
#Test(expected = MonitoringException.class)
public void createCustomMetricGetsNonNullResponse() throws MonitoringException {
CreateCustomMetricRequest mockRequest = CreateCustomMetricRequest.builder()
.displayName(DISPLAY_NAME)
.types(new String[] {"test-type"})
.build();
CreateCustomMetricResponse response = CreateCustomMetricResponse.builder()
.displayName(DISPLAY_NAME)
.types(new String[] {"test-type"})
.timeseriesId(TIMESERIES_ID)
.build();
boolean val = true;
when(monitoringUtilsMock.isValidMetricIdValue(anyString())).thenReturn(val);
when(httpUtilsMock.postCustomMetric(API_URL + "/v1/timeseries/" + METRIC_ID, API_TOKEN, mockRequest)).thenReturn(response);
CreateCustomMetricResponse actualRespnose = dynatraceAPIServiceImpl.createCustomMetric(mockRequest);
//verify(httpUtilsMock, times(1)).postCustomMetric(anyString(), anyString(), any(CreateCustomMetricRequest.class));
//assertEquals(actualRespnose.getDisplayName(), DISPLAY_NAME);
}
}
Here, when I execute the tests, it always end up having the response value to be null in line
CreateCustomMetricResponse response = httpUtils.postCustomMetric(apiUrl + "/v1/timeseries/" + metricId, apiToken, request);
Even if I have used when() statement to return response as I have created, it is returning null.
Really appreciate if someone can let me know what is wrong here. Thanks.
That normally happens when the params your production code uses differ from the ones that you stubbed the call with, an easy way to find out is to write the test like this
when(httpUtilsMock.postCustomMetric(any(), any(), any())).thenReturn(response);
CreateCustomMetricResponse actualRespnose = dynatraceAPIServiceImpl.createCustomMetric(mockRequest);
verify(httpUtilsMock).postCustomMetric(API_URL + "/v1/timeseries/" + METRIC_ID, API_TOKEN, mockRequest);
If you do that, you'll get a nicer error showing the difference between what your code did and what you verified it for
A better approach in general is to use 'strict stubs' so if your code does anything different to what you stubbed the mock for you'll get a nice error telling you what, where and why

updating JSON Object in spring restful web services

I want to pass a json object for the update function but its doesn't accept the json object and get an error. The error is:
the code is:
(value = "/UpdateUser/", method = RequestMethod.PUT , consumes=MediaType.APPLICATION_JSON_VALUE)
public void UpdateUser(JSONObject RequiredObject)throws UnknownHostException {
// RequiredObject=new HashMap<>();
System.out.println("hello into update " + RequiredObject);
// readJSON.UpdateUser(RequiredObject);
}
you have to receive the body of your request as a #RequestBody and you can receive this json object as a User object directly
#RequestMapping(value = "/UpdateUser/", method = RequestMethod.PUT ,
consumes=MediaType.APPLICATION_JSON_VALUE)
public void UpdateUser(#RequestBody User user) throws UnknownHostException {
// RequiredObject=new HashMap<>();
System.out.println("hello into update " + RequiredObject);
//readJSON.UpdateUser(RequiredObject);
}

sending arraylist from a rest service

I am new to webservices and also REST. I am trying to send a message as a post request to a rest service using rest java client.I am trying to get response of previous requests also(everything in json format). So, am storing the message objects into an arraylist and sending the list as a reponse. But I am not able to get the previous messages. Please tell me if am doing anything wrong.
This is my message model class.
public class Messages {
private String id;
private String message;
public Messages() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
the following is my webservice to receive a message object and return a json array.
#Path("/json/messages")
public class JSONMessages {
public List<Messages> list = new ArrayList<Messages>();
List<Messages> getAllMessages(Messages m){
list.add(m);
return list;
}
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response MessageListInJSON(Messages msg) {
System.out.println("message saved");
if(!(msg.getId().equals("1"))){
String output ="Invalid User";
return Response.ok(output).build();
}
else{
return Response.ok(getAllMessages(msg)).build();
}
}
}
Finally, the following is my client side code
public class ClientPost {
public static void main(String[] args) {
try {
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
WebResource webResource = client
.resource("http://localhost:8050/lab.rest.webservices/rest/json/messages/post");
//for(int i=0;i<5;i++){
String input = "{\"id\":\"1\", \"message\":\"hey there!\"}";
ClientResponse response = webResource.accept("application/json").type("application/json")
.entity(input).post(ClientResponse.class);
if (response.getStatus() !=200 ) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
System.out.println("Output from Server .... \n");
String output = response.getEntity(String.class);
System.out.println(output+"\n");
}
catch (Exception e) {
e.printStackTrace();
}
} }
Now, what I am expecting to see is the message I sent along with the previous responses stored in the array list(which were sent by running the client multiple times manually for now) but always am ending up with only the current message.
output:
Output from Server ....
[{"id":"1","message":"hey there!"}]
To be precise, what I want as output when i run my client several times(or put the try block in loop) is as follows which i am unable to get.
Output from Server ....
[{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"},{"id":"1","message":"hey there!"}] .
Resources in JAXRS aren't singletons. That means that for each request, the class JSONMessages is instantiated. So you lose the content of the attribute list. Changing it to static could fix your problem.
There is an annotation Singleton to change this behavior. In this case the resource will be managed as singleton and not in request scope. Here is a sample:
#Singleton
#Path("/json/messages")
public class JSONMessages {
(...)
}
Otherwise, be careful of concurrent accesses on your list. See this question for more details: java concurrent Array List access.
Hope it helps you,
Thierry