I am currently converting a node project to DW. The node project currently stores JSON from the client as a string and then returns application/JSON when the client gets the same resource. This is basically a Key/value store reset endpoint.
I want to implement the same with dropwizard, but I do not want to map out the entire structure and it's nested structures in POJOs. Is there a way to allow for this? I just want to save the JSON as a string in the db with the key, I do not want to work with the data at all in the java application.
Since the APIs require that I return an object, what should the object be? Here is the function I have for DW, as you can see it is expecting to return an object.
#GET
#UnitOfWork
#Timed
#ApiOperation(value="Find value by ID", notes="Get a value object from the DAO using ID as the sole criterion")
#ApiResponses(value={
#ApiResponse(code=400, message="Invalid ID"),
#ApiResponse(code=404, message="No object found by specified ID")
})
public SomeJavaOjbectMustGoHere getSample(
#ApiParam(value="id of object to get", required=true)
#QueryParam("id")
Long id
) throws WebApplicationException {
SomeJavaOjbectMustGoHere returned = dao.get(id);
if (returned == null) throw new WebApplicationException(Response.Status.NOT_FOUND);
else return returned;
}
Here is most of the code from node:
module.exports = function (server) {
function createResponse(req, res, next) {
var key = req.params.name;
console.log("Creating Response for key: '" + req.params.name + "'");
// ...some validation...
if (..blah..) {
// fail out.
res.send(403, "response can not be saved without a valid key and structure.");
return next();
}
var data = JSON.stringify(req.body);
// ... store the stuff in the db...
res.send(201, "Saved");
return next();
}
function getResponse(req, res, next) {
try {
var payload = {};
// ... get the data matching the key...
res.header("Content-Type", "application/json");
res.send(200, JSON.parse(payload.toString()));
}
catch(err) {
console.log('Data not found.' + err);
res.send(200,
{
"id": Math.random().toString(36).substr(3, 8),
// ... default structure ...
});
}
return next();
}
function send(req, res, next) {
res.send('response ' + req.params.name);
return next();
}
server.post('/response/:name', createResponse);
server.put('/response', send);
server.get('/response/:name', getResponse);
server.head('/response/:name', send);
server.del('/response/:name', function rm(req, res, next) {
res.send(204);
return next();
});
}
If you don't want to create your own Object model then Jackson has a JsonNode class.
If you don't want to do anything with the data you could just return a String and add the following annotation to your method:
#Produces(MediaType.APPLICATION_JSON)
Related
I have the following API-method:
#PatchMapping("/{id}")
public ResponseEntity<?> partialProjectUpdate(#PathVariable long id, #RequestBody EntryStatus status) throws DailyEntryNotFoundException {
return dailyEntryService.partialDailyEntryUpdate(id, status);
}
EntryStatus is an enum:
public enum EntryStatus {
OPEN,
PROGRESS,
CHECKED,
BOOKED,
UNAVAILABLE;
private static Map<String, EntryStatus> namesMap = new HashMap<String, EntryStatus>(3);
static {
namesMap.put("OPEN", OPEN);
namesMap.put("PROGRESS", PROGRESS);
namesMap.put("CHECKED", CHECKED);
namesMap.put("BOOKED", BOOKED);
namesMap.put("UNAVAILABLE", UNAVAILABLE);
}
#JsonCreator
public static EntryStatus forValue(String value) {
return namesMap.get(value);
}
#JsonValue
public String toValue() {
for (Map.Entry<String, EntryStatus> entry : namesMap.entrySet()) {
if (entry.getValue() == this)
return entry.getKey();
}
return null; // or fail
}
}
I call the method in typescript like this:
partialUpdateDailyEntry(dailyEntry: DailyEntry, status): Observable<any> {
const statusName: string = status.name;
return this.http.patch(BASE_URL + dailyEntry.id, statusName, this.authService.setHeaders('application/json'))
.pipe(
catchError(this.handleService.error)
);
}
statusName is a string, but the problem is that its getting sent without quotemarks via JSON. The RequestBody is for example OPEN instead of "OPEN" which gives me the following error:
JSON parse error: Unrecognized token 'OPEN': was expecting ('true', 'false' or 'null').
As stated thats caused by the fact that the string is sent without quotemarks.
I could fix that problem by adding the quotemarks manually to statusName like this:
const statusName: string = '"' + status.name + '"';
But that cant be the proper solution, is there a better way to do it?
Try with
#JsonFormat(shape = JsonFormat.Shape.STRING)
public enum EntryStatus{
OPEN,
PROGRESS,
CHECKED,
BOOKED,
UNAVAILABLE;
}
maybe you could put
namesMap.put("OPEN", OPEN);
as
namesMap.put("\"OPEN\"", OPEN);
You are adding the header that you are sending JSON, but "OPEN" is not a valid JSON value.
You should either change your headers:
this.authService.setHeaders('text/plain')
Or change how you send it:
this.http.patch(BASE_URL + dailyEntry.id, { status: statusName});
And change your java backend to handle to receive the object and read the status
Or stringify it before sending it:
const statusName: string = JSON.stringify(status.name);
I want to invoke series of API calls in Java. The requirement is that some API's response will be used in the subsequent API call's request. I can achieve this using certain loops. But I want to use a design pattern in such a way that the implementation is generic. Any help?
Chain of responsibility doesn't serve my need as I won't be knowing what is my request context in the beginning.
String out = null;
Response res = execute(req);
out += res.getOut();
req.setXYZ(res.getXYZ);
Response res = execute(req);
out += res.getOut();
req.setABC(res.getABC);
Response res = execute(req);
out += res.getOut();
System.out.println("Final response::"+out);
The following come to mind:
For function calls that return an object: never return null.
For function calls that do not (otherwise) return anything: return this.
Accept functional interfaces in your API so users can customize behavior
For stateful objects that expose API as described above, provide a Builder pattern so users don't end up choosing between constructors
All methods of the Builder described must be void, and therefore return this
You can create a ResponseStringBuilder class that takes a Function<Response,String> to get the String from the Response.
public ResponseStringBuilder {
private Request request;
public StringBuilder resultBuilder = new StringBuilder();
public ResponseBuilder(Request req) {
this.request = req;
}
public ResponseStringBuilder fromExtractor(Function<Request, Response> getResponse, Function<Response,String> extract) {
Response response = getResponse.apply(request);
resultBuilder.append(extract.apply(response));
return this;
}
public String getResult() {
return resultBuilder.toString();
}
}
That would make your calls
ResponseStringBuilder builder = new ResponseStringBuilder(req);
#SuppressWarnings("unchecked")
Function<Response,String> extractors = new Function[] {
Response::getABC, Response::getXYZ
};
for (Function<Response,String> ext : extractors) {
builder = builder.fromExtractor(this::execute, ext);
}
System.out.println("final response: " + builder.getResult());
Not sure if the array declaration actually compiles, but it should work with minor modification and you get the gist.
You can use a CompletableFuture to implement promises in Java. The problem is, you're trying to pass two different things down the 'pipeline:' the request, which is mutable and (sometimes) changes, and the result, which is accumulated over the course of the calls.
I've gotten around that by creating a class called Pipe which has a request, and the accumulator for the results so far. It has getters for both, and it has a few convenience methods to return a new object with the accumulated results or even mutate the request and accumulate in one call. This makes the code of the API chaining a lot cleaner.
The with* methods after the fields, constructor, and getters are the ones that handle the accumulation and mutation. The chain method puts it all together:
import java.util.concurrent.CompletableFuture;
public class Pipe {
private Request req;
private String out;
public Pipe(Request req, String out) {
this.req = req;
this.out = out;
}
public Request getReq() {
return req;
}
public String getOut() {
return out;
}
public Pipe with(String data) {
return new Pipe(req, out + data);
}
public Pipe withABC(String abc, String data) {
req.setABC(abc);
return new Pipe(req, out + data);
}
public Pipe withXYZ(String xyz, String data) {
req.setXYZ(xyz);
return new Pipe(req, out + data);
}
public static void chain(Request req) throws Exception {
var promise = CompletableFuture.supplyAsync(() -> new Pipe(req, ""))
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.withABC(res.getABC(), res.getOut());
})
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.withXYZ(res.getXYZ(), res.getOut());
})
.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.with(res.getOut());
});
var result = promise.get().getOut();
System.out.println(result);
}
public static Response execute(Request req) {
return req.getResponse();
}
}
Because it runs asynchronously, it can throw InterruptedException, and it can also throw ExecutionException if something else breaks. I don't know how you want to handle that, so I just declared chain to throw.
If you wanted to apply n operations in a loop you have to keep reassigning the promise back, as follows:
var promise = CompletableFuture.supplyAsync(() -> new Pipe(req, ""));
for (...) {
promise = promise.thenApply(pipe -> {
Response res = execute(pipe.getReq());
return pipe.with(res.getOut());
});
}
var result = promise.get().getOut();
I've used Java 10 type inference with var here, but the types of promise and result would be CompletableFuture<Pipe> and String, respectively.
(Note: it might be better to make Request immutable and pass a new, altered one down the pipeline rather than mutating it. On the other hand, you could also wrap a StringBuilder instead of a String, and have the data you're accumulating be mutable, too. Right now it's an odd mix of mutable and immutable, but that matches what your code was doing.)
Thanks all for the inputs, finally I landed on one solution which meets my need. I used one Singleton for the request execution. For each type of command, there will a set of requests to be executed in one particular order. Each command is having a particular order of requests to be executed which I stored in an array with request's unique ID. Then kept the array in a map against command name.
In a loop, I ran the array and executed, after each iteration I keep setting the response back into the request object and eventually prepared the output response.
private static Map<RequestAction,String[]> actionMap = new HashMap<RequestAction, String[]>();
static{
actionMap.put(RequestAction.COMMAND1,new String[]{WebServiceConstants.ONE,WebServiceConstants.TWO,WebServiceConstants.FOUR,WebServiceConstants.THREE});
actionMap.put(RequestAction.THREE,new String[]{WebServiceConstants.FIVE,WebServiceConstants.ONE,WebServiceConstants.TWO});}
public Map<String,Object> execute(ServiceParam param) {
String[] requestChain = getRequestChain(param);
Map<String,Object> responseMap = new HashMap<String, Object>();
for(String reqId : requestChain) {
prepareForProcessing(param, tempMap,responseMap);
param.getRequest().setReqId(reqId);
//processing the request
tempMap = Service.INSTANCE.process(param);
//prepare responseMap using tempMap
param.setResponse(response);
}
return responseMap;
}
I have server written in Java, where I create JSON objects like this:
#Override
public void serialize(Net net, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
try {
Set<Place> places = net.getPlaces();
Set<Transition> transitions = net.getTransitions();
JSONObject jsonPlaces = new JSONObject();
for (Place p : places)
{
String id = p.getId();
double xCoord = p.getxCoord();
double yCoord = p.getyCoord();
JSONObject jsonPosition = new JSONObject();
jsonPosition.put("x", xCoord);
jsonPosition.put("y", yCoord);
JSONObject jsonPlace = new JSONObject();
jsonPlace.put("position", jsonPosition);
jsonPlaces.put(id, jsonPlace);
}
jg.writeRawValue(jsonPlaces.toString());
} catch (Exception ex) {
throw new IOException("...", ex);
}
}
The resulting object as string (jsonPlaces.toString()) looks like this:
{"id01":{"position":{"x":220,"y":90}},"id02":{"position":{"x":210,"y":250}}}
I send it to my web application using the code below, it uses the serialize() method..
#POST
#Path("/blindLayout")
#Consumes(MediaType.APPLICATION_JSON)
public Net blindLayout(Net net) throws Exception {
.
.
return net;
}
And here is the angularjs code that should recieve the response
.factory('Layout', function ($http, Notification, AnalysisConfig) {
layoutPrototype.performLayout = function (net, options, defered) {
if (net) {
var address = AnalysisConfig.serverAddress + AnalysisConfig.resourceURI + AnalysisConfig.resources.blindLayout;
$http.post(address, JSON.stringify(net), {timeout: AnalysisConfig.timeout})
.then(function (response) {
var data = response;
},
function (response) {
Notification.error({
title: 'Communication error',
...
});
});
};
};
My problem is that I canĀ“t get data from the response. No matter what I tried, the result is always undefined or [object Object]. So how should I get data from response so I can for example use alert() and write something like
id01 (value of x, value of y)
id02 (value of x, value of y)
...
so I can also use it in my app?
the $http returns a promise that's resolved with an object that contains more than just the body but also headers and status. So to retrieve the JSON you created on a backend you can do:
$http.post(address, JSON.stringify(net), {timeout: AnalysisConfig.timeout})
.then(function (response) {
var data = response.data;
},
and then if you want to iterate over object keys you can do few things
for(var id in data){
console.log(data[id]) //{"position":{"x":220,"y":90}}
console.log(data[id].position) //{"x":220,"y":90}
}
or
var arrayOfObjects = Object.keys(data).map(function(id){
return data[id].position;
});
console.log(arrayOfObjects) // [{"x":220,"y":90}, {"x":210,"y":250}]
Hi I have a simple Rest service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Product createProduct(Product product) {
if (!(productDao.findByName(product.getProductName()).isEmpty())) {
//?????
} else {
productDao.create(product);
//?????
}
return product;
}
When input name is incorrect and method findByName return not null I want return from my rest service method to angular only information, example "Product exist". When method findByName return null and product is created I want return Product from my method to Angular controller. How handle it? Return entity and information?
And what I handle it in my angular controller? Below controller wokrs good when I return entity, but I don't now why handle information "Product exist" not entity?
$scope.addProduct = function (product) {
$http.post(serviceURI + "products", product).success(function (data) {
$scope.products.push(data);
$('.success-message').fadeIn(1000).delay(5000).fadeOut(1000);
$scope.message = "Product added";
}).error(function (error) {
$('.error-message').fadeIn(1000).delay(5000).fadeOut(1000);
$scope.message = "Error";
});
}
How is the best practice to return data and information from JAX-RS and get it in Angular controller?
Since RESTFul webservices work with the HTTP vocabulary I suggest to return different HTTP status codes depending on the outcome of your operations.
In the first case you could throw a WebApplicationException with a status code of the 4xx family.
In the second case you could use the default status code (I think it would be 200 in this case) or provide a more specific status code such as 201 (Created) by returning a Response object instead of a Product directly.
Eg. Response.created might help you.
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
In my case, I use JAX-RS for the input and Gson for the output when the response is ok because I need to manipulate dates (long/Calendar) and with Gson is easy to add adapters. When the response is not ok, I return a status error code.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Product createProduct(Product product) {
try {
Gson gson = new GsonBuilder()
//.registerTypeAdapter(Calendar.class, new CalendarSerializer())
// .registerTypeAdapter(Calendar.class, new CalendarDeserializer())
// .registerTypeAdapter(GregorianCalendar.class,
// new CalendarSerializer())
.create();
String json = null;
//do something
json = gson.toJson(product);
return Response.ok(json, MediaType.APPLICATION_JSON).build();
}catch (IllegalArgumentException ex){
return Response.serverError().status(Status.BAD_REQUEST).build();
}catch (Exception ex) {
return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build();
}
finally{
}
}
Client with AngularJs:
.success (function(data) {
//ok -> get data
})
.error (function(resp) {
if (resp.errorCode == 400){
...
}
...
...
}
I am following this tutorial on uploading files to a server from android, but I cannot seem to get the code right on the server side. Can somebody please help me code the Web Api post method that would work with that android java uploader? My current web api controller class looks like this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
namespace WSISWebService.Controllers
{
public class FilesController : ApiController
{
// GET api/files
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/files/5
public string Get(int id)
{
return "value";
}
// POST api/files
public string Post([FromBody]string value)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
try
{
Stream fileStream = File.Create(HttpContext.Current.Server.MapPath("~/" + value));
requestStream.CopyTo(fileStream);
fileStream.Close();
requestStream.Close();
}
catch (IOException)
{
// throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
}
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response.ToString();
}
// PUT api/files/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/files/5
public void Delete(int id)
{
}
}
}
I am pretty desperate to get this working as the deadline is tuesday. If anybody could help that would be much appreciated.
you can post a files as multipart/form-data
// POST api/files
public async Task<HttpResponseMessage> Post()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
string value;
try
{
// Read the form data and return an async data.
var result = await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
// return multiple value from FormData
if (key == "value")
value = val;
}
}
if (result.FileData.Any())
{
// This illustrates how to get the file names for uploaded files.
foreach (var file in result.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
if (fileInfo.Exists)
{
//do somthing with file
}
}
}
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, value);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = files.Id }));
return response;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}