I am attempting to get some data from a database to load into a React based component in my front end. In order to do this, I have created a fetch request that talks to a java based controller on the backend that then eventually hits the database and pulls the information from the database. However, when I attempt to maven build the project, it fails repeatedly and provides the error "TypeError: Cannot read property 'then' of undefined" which from searching implies a Promise isn't being returned by the fetch request.
My assumption based on several tests is that my fetch request isn't actually being directed to my controller somehow (and debugging the build fails to hit a breakpoint within the controller as well). Looking for any assistance to see why these two pieces aren't talking to each other.
I should also mention I have an insert method in the same view portion that talks to the same controller and that works successfully.
Controller Portion:
#Component
#RestController
#RequestMapping(value="/api/process/")
public class ProcessController {
private final ProcessService processService;
#Autowired
public ProcessController(ProcessService processService) { this.processService = processService; }
#RequestMapping(value="add", method = RequestMethod.POST)
public ResponseEntity<String> insertProcess(#RequestBody() String processJson) {
Gson gson = new Gson();
Process process = gson.fromJson(processJson, Process.class);
try {
return new ResponseEntity<>(gson.toJson(processService.insertProcess(process)), HttpStatus.OK);
} catch(DataAccessException de) {
return new ResponseEntity<>(de.getCause().getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#RequestMapping(value="select", method = RequestMethod.POST)
public ResponseEntity<String> selectProcesses() {
try {
return new ResponseEntity<>(new Gson().toJson(processService.selectProcesses()), HttpStatus.OK);
} catch(DataAccessException de) {
return new ResponseEntity<>(de.getCause().getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
And the fetch calls:
class ProcessApi {
static addProcess(processJson) {
return fetch('/api/process/add', {
method: 'POST',
body: processJson
})
.then(response => {
if(response.status === 200) {
return response.json()
.then(jsonData => {
return jsonData;
});
}
})
.catch((error) => {
console.error(error);
return error.json();
});
};
static getProcesses() {
return fetch('/api/process/select', {
method: 'POST'
})
.then(response => {
if(response.status === 200) {
return response.json()
.then(jsonData => {
return jsonData;
});
}
})
.catch((error) => {
console.error(error);
return error.json();
});
};
}
As mentioned, the "addProcess" portion works just fine. The select just isn't connecting up and I can't seem to find out why. For reference I have the API call happening in the componentDidMount() method in my view portion.
Related
I have a code with a RestBuilder that needs to connect to another application, the target endPoint have an object in the signature with the attributes. The problem is the request return 404. How I solve this? I tried use x-www-form-urlencoded (doesn't work)
Request Method:
RestResponse restResponse;
String parameters = '{"qtdThreads":3,"channel":"http://localhost:8081/application2"}'
try {
restResponse = new RestBuilder().post("http://localhost:8080/application/endPoint", {
accept("application/json")
contentType "application/json; utf-8"
body(parameters.getBytes("UTF-8"))
connectTimeout: 1000
})
} catch (Exception e) {
e.printStackTrace();
} finally {
return restResponse;
}
Target endPoint:
Object endPoint(ObjectCommand command) {
render(status: HttpStatus.OK)
}
Object used on signature
import grails.validation.Validateable
#Validateable
class ObjectCommand {
URL channel
Integer qtdThreads
static constraints = {
qtdThreads(validator: { Integer val ->
if (!val || val <= 0) {
return "message1"
}
})
channel(validator: { URL val ->
if (!val) {
return "message2"
}
})
}
}
did you check if the target application is running and exposing that endpoint?
We are developing a project Using Spring boot with DGS Netflix graphql. We are created all the schemas and datafethers which is working absolutely fine with a default endpoint "/graphql". we would like to expose this app with custom endpoing so we are trying to add a controller with a custom endpoint as below. But When i run the application and send a query, my data fetcher is called twice . first time called from controller and second time i believe from framework it self. Anybody has any thoughts on this why its being called twice and how to avoid it? You help is highly appreciated. Please see the below Datafetcher and Controller.
Controller:
#RestController
#RequestMapping("/sample-information/model")
#Slf4j
public class CustomController {
#Autowired
DgsQueryExecutor dgsQueryExecutor;
#PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, "application/graphql"})
public Mono<ResponseEntity<Object>> getDetails(#RequestBody String query,
#RequestHeader HttpHeaders headers
) {
GraphQLQueryInput inputs = null;
try {
inputs = ObjectMapperHelper.objectMapper.readValue(query, GraphQLQueryInput.class);
} catch (Exception e) {
log.error("TraceId: {} - Application Error: Error message: Error converting query to GraphQLQueryInput: {} "+ query);
}
if(inputs.getVariables() == null) {
inputs.setVariables(new HashMap<>());
}
if(inputs.getOperationName() == null) {
inputs.setOperationName("");
}
final String que = inputs.getQuery();
final Map<String, Object> var = inputs.getVariables();
final String opn = inputs.getOperationName();
ExecutionInput.Builder executionInput = ExecutionInput.newExecutionInput()
.query(inputs.getQuery())
.operationName(inputs.getOperationName())
.variables(inputs.getVariables());
return Mono.fromCallable(()-> {
return dgsQueryExecutor.execute(que, var, opn);
}).subscribeOn(Schedulers.elastic()).map(result -> {
return new ResponseEntity<>(result, HttpStatus.OK);
});
}
}
Datafetcher:
#DgsComponent
#Slf4j
public class SampleDataFetcher {
#Autowired
SampleBuilder sampleBuilder;
#DgsData(parentType = DgsConstants.QUERY_TYPE, field = DgsConstants.QUERY.SampleField)
public CompletableFuture<StoreDirectoryByStateResponse> getStoreDirectoryByState(#InputArgument String state, DataFetchingEnvironment dfe) throws BadRequestException {
Mono<StoreDirectoryByStateResponse> storeDirectoryResponse = null;
try {
sampleResponse = sampleBuilder.buildResponse(modelGraphQLContext);
} catch (BaseException e) {
}
return sampleResponse.map(response -> {
return response;
}).toFuture();
}
}
I am trying to return a response from server.
Take the example of adding a car to the server, my AngularJS factory is the following:
app.factory('CarServices', function ($resource) {
return $resource('/ws/cars', {}, {
query: { method: 'GET', isArray: true },
create: { method: 'POST' },
delete: { method: 'DELETE', params: {id: '#id'} }
})
});
Then, In my CarController I have this function:
// callback for ng-click 'addCar':
$scope.addCar= function () {
$scope.car = { "plate": "778899", "brand": "Ferrari" };
CarServices.create($scope.car).$promise.then(function() {
// If success, show success message
}, function(error) {
// If error, show message from server
});
}
I am using Java with RESTful WebServices and this is my WebService:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response addCar(JsonCar jc) {
Car car = new Car(jc.getPlate(), jc.getBrand());
if(car.getByPlate()) {
return Response.ok().build();
} else {
return Response.status(Response.Status.NOT_ACCEPTABLE)
.entity("Car does not exist on database").build();
}
}
So, I wan't that in case of error on the controller, show the message "Car does not exist on database" but instead of that I am getting this error (console.log(error)):
json.parse unexpected end of data at line 1 column 1 of the json data
Thank you.
Java - spring controller - Angularjs form submission
Problem is with "#RequestBody OfferForm data" when i submit form i get error "404 bad request" but when i replace OfferForm bean with String object it works fine and display form data in json format.
any help appreciated.
Following is my angularjs function code
$scope.submitOffer = function() {
alert('submitOffer')
$http({method: 'POST', url: '/offer/submitOffer', data: $scope.formData}).
success(function(data, status, headers, config) {
$scope.successMsg = data;
}).
error(function(data, status, headers, config) {
if(status == 400) {
$scope.errMessages = data;
} else {
alert('Unexpected server error.');
}
});
};
Following is my controller code
#RequestMapping(value="offer")
public class OfferController{
#RequestMapping(value = "/submitOffer", method = RequestMethod.POST)
#ResponseBody public ResponseEntity<?> postForm(#RequestBody OfferForm data) {
System.out.println(data);
return new ResponseEntity<String>("Offer Created", HttpStatus.OK);
}
}
Following is my java bean
public class OfferForm {
private String offerType;
private String offerTitle;
public String getOfferType() {
return offerType;
}
public void setOfferType(String offerType) {
this.offerType = offerType;
}
public String getOfferTitle() {
return offerTitle;
}
public void setOfferTitle(String offerTitle) {
this.offerTitle = offerTitle;
}
}
Your $scope.formData object has more property than expected by the webservice.
You should provide to your webservice an object which has at most two properties of type string: offerType and offerTitle.
I think you currently have more properties than expected or you don't have the correct type, thus the bad request exception.
You could do something like that in your javascript, given that the two properties are a string:
$scope.submitOffer = function () {
$http({
method: 'POST',
url: '/offer/submitOffer',
data: {
offerType: $scope.formData.offerType,
offerTitle: $scope.formData.offerTitle
}
}).
success(function (data, status, headers, config) {
$scope.successMsg = data;
}).
error(function (data, status, headers, config) {
if (status == 400) {
$scope.errMessages = data;
} else {
alert('Unexpected server error.');
}
});
};
I get following response when I try to delete: 405 Method Not Allowed.
In my logs there is written that GET is allowed, but DELETE isn't.
Java:
#ResponseBody
#RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
public void delete(#PathVariable String id) {
speakerService.delete(id);
}
Angularjs
app.factory('SpeakerResource', function ($resource) {
return $resource('rest/speaker/:speakerId',
{
speakerId: '#speakerId'
},
{
'update': { method: 'PUT' }
},
{
'delete': { method: 'DELETE', params: { 'id': 'speakerId' }}
}
)
});
SpeakerService
this.delete = function (id, callback) {
SpeakerResource.delete({ speakerId: id }, function () {
callback();
});
}
I do not know your complete code, and I am not an expert in AngularJS, but it looks like your want to send a DELETE request to the URL <hopefullySomething>/{id} (Path variable). But it looks like that you send a DELETE request so some URL with an parameter id <hopefullySomething>?id={id} (Request parameter).
This question and answers explain the difference between path variable and request parameters a bit more #RequestParam vs #PathVariable
use $http.delete(), and return data for example status, I just tested the following with spring and working correctly
#RequestMapping(value = "delete/{id}", method = RequestMethod.DELETE)
public #ResponseBody Status deletePerson(#PathVariable("id") int id) {
try {
personService.removePerson(id);
return new Status(1, "person deleted Successfully !");
} catch (Exception e) {
return new Status(0, e.toString());
}
}
angular
angular.module('personService', [])
.factory('Person', ['$http',function($http) {
return {
deletePerson: function(id) {
return $http.delete('/restperson/delete/'+id);
}
}
}]);
controller
angular.module('personController', [])
// inject the person service factory into our controller
.controller('mainController', ['$scope','$http','Person', function($scope, $http, Person) {
//delete
$scope.deletePerson = function(id) {
Person.deletePerson(id)
.success(function(data) {
$scope.message = data;
});
};
}]);