Grails RestBuilder dont findendPoint with Object in signature - java

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?

Related

Controller in DGS Netflix Graphql

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();
}
}

Micronaut get handling object/method in Filter

So i have following controller
Controller("/test")
public class MyController {
#Get("/anno")
#MyAnnotation(value="my annotation value") // <---- i want this value
public Object testAnnotation(HttpRequest<?> request){
return "Hello world";
}
}
I'm trying to implement custom filter on micronauts http server.
#Filter("/**")
public class MyFilter implements HttpServerFilter {
#Override
public Publisher<? extends HttpResponse<?>> doFilter(HttpRequest<?> request, FilterChain chain) {
// HERE
// how to get the MyAnnotation value from the handling method for the request ?
return chain.proceed(request);
}
}
How to get my custom annotation inside the filter ?
Thank you.
You would need AOP, Micronauts supports it. But you get it from a MethodInterceptor, not HttpFilter. Here is the code I modified based on what I wrote for tracing, in Kotlin, it would be very similar in Java:
#Singleton
#InterceptorBean(MyAnnotation::class)
class MyAnnotationInterceptor : MethodInterceptor<Any, Any> {
override fun intercept(context: MethodInvocationContext<Any, Any>): Any? {
val myAnnotation: AnnotationValue<MyAnnotation> = context.getAnnotation(MyAnnotation::class.java)!!
val value = myAnnotation.get("value", String::class.java).orElse(null)
val className = context.declaringType.simpleName
val methodName = context.methodName
val operationName = "$className.$methodName"
val interceptedMethod = InterceptedMethod.of(context)
try {
when (interceptedMethod.resultType()) {
SYNCHRONOUS -> {
try {
return context.proceed()
} catch (e: Exception) {
throw e
} finally {
}
}
COMPLETION_STAGE -> {
try {
var completionStage = interceptedMethod.interceptResultAsCompletionStage()
return interceptedMethod.handleResult(completionStage)
} catch (e: Exception) {
logError(newSpan, e)
throw e
}
}
else -> return interceptedMethod.unsupported()
}
} catch (e: Exception) {
return interceptedMethod.handleException<RuntimeException>(e)
}
}
}
val value = myAnnotation.get("value", String::class.java).orElse(null) is where you get the value.
We use the above code to extract the tracing sampling rate and it works well for us. Note that your annotation will need "around" AOP annotation:
#Retention(RUNTIME)
#Target(CLASS, FILE, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
#Around
annotation class MyAnnotation(
val value: String = "",
)

How to change base URL using retrofit2 and koin 2.0

I have a query that returns a list of servers, and the user can select the server he needs.
Googling did not help, almost no results.
Tell me how to implement basic URL spoofing in real time using Koin and Retrofit?
My Modules:
fun createMainModule(context: Context) = module {
single(named(APP_CONTEXT)) { context }
single(named(RESOURCES)) { context.resources }
single(named(REPOSITORY)) {
Repository(get(named(RETROFIT)))
}
}
fun createNetworkModule(baseUrl: String) = module(override = true) {
single(named(TOKEN_INTERCEPTOR)) { createTokenInterceptor(get(named(DATA_PROVIDER))) }
single(named(OK_HTTP)) { createOkHttpClient(get(named(TOKEN_INTERCEPTOR))) }
single(named(GSON)) { createGson() }
single(named(RETROFIT)) {
createRetrofit(
get(named(RESOURCES)),
get(named(LOG_OUT_SUBJECT)),
get(named(GSON)),
baseUrl,
get(named(OK_HTTP))
)
}
I resolve my problem with comment #sonnet
This code:
class ChangeableBaseUrlInterceptor : Interceptor {
#Volatile
private var host: HttpUrl? = null
fun setHost(host: String) {
this.host = host.toHttpUrlOrNull()
}
fun clear() {
host = null
}
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
var request = chain.request()
host?.let {
val newUrl = request.url.newBuilder()
.scheme(it.scheme)
.host(it.toUrl().toURI().host)
.port(it.port)
.build()
request = request.newBuilder().url(newUrl).build()
}
return chain.proceed(request)
}
}

How to combine Flux and ResponseEntity in Spring Webflux controllers

I use Monos with ResponseEntitys in my Webflux controllers in order to manipulate headers and other response info. For example:
#GetMapping("/{userId}")
fun getOneUser(#PathVariable userId: UserId): Mono<ResponseEntity<UserDto>> {
return repository.findById(userId)
.map(User::asDto)
.map { ResponseEntity.ok(it) }
.defaultIfEmpty(ResponseEntity.notFound().build())
}
#GetMapping
fun getAllUsers(): Flux<UserDto> {
return repository.findAllActive().map(User::asDto)
}
both works fine but there are cases where it is required to have ResponseEntity in conjunction with Flux as well. What should the response type be? Is it correct to use ResponseEntity<Flux<T>>?
For example:
#GetMapping("/{userId}/options")
fun getAllUserOptions(#PathVariable userId: UserId): ??? {
return repository.findById(userId)
.flatMapIterable{ it.options }
.map { OptionDto.from(it) }
// if findById -> empty Mono then:
// return ResponseEntity.notFound().build() ?
// else:
// return the result of `.map { OptionDto.from(it) }` ?
}
The behaviour I'd like to achieve here is that getAllUserOptions returns 404 if repository.findById(userId) is an empty Mono, otherwise return user.options as Flux.
Update:
repository here is ReactiveCrudRepository
Use switchIfEmpty to throw an exception in case the user doesn't exist:
return repository
.findById(userId)
.switchIfEmpty(Mono.error(NotFoundException("User not found")))
.flatMapIterable{ it.options }
.map { OptionDto.from(it) }
Then with an exception handler translate it to a 404 response.
You can use by returning Mono with ResponseEntity
like this
public Mono<ResponseEntity<?>> oneRawImage(
#PathVariable String filename) {
// tag::try-catch[]
return imageService.findOneImage(filename)
.map(resource -> {
try {
return ResponseEntity.ok()
.contentLength(resource.contentLength())
.body(new InputStreamResource(
resource.getInputStream()));
} catch (IOException e) {
return ResponseEntity.badRequest()
.body("Couldn't find " + filename +
" => " + e.getMessage());
}
});
}
I have also example like this
public ResponseEntity<Mono<?>> newLive(#Valid #RequestBody Life life) {
Mono<Life> savedLive = liveRepository.save(life);
if (savedLive != null) {
return new ResponseEntity<>(savedLive, HttpStatus.CREATED);
}
return new ResponseEntity<>(Mono.just(new Life()), HttpStatus.I_AM_A_TEAPOT);
}
I dislike functional programming in the REST controllers.
Here is an example ReactiveController .
works for me, let me know if you have a trouble
#PostMapping(value = "/bizagi/sendmsg")
public Mono<ResponseEntity<?>> sendMessageToQueue(#RequestBody BizagiPost bizagiPost) {
Mono<BodyReturn> retorno = useCase.saveMsg(bizagiPost);
Map<String, Object> response = new HashMap<>();
return retorno.map(t ->
{
if (t.getStatusCode().equals("200")) {
response.put("message", t.getReazon());
return new ResponseEntity(t, HttpStatus.OK);
} else {
response.put("message", t.getReazon());
return new ResponseEntity(t, HttpStatus.BAD_REQUEST);
}
});
}

Error 405 Method Not Allowed error, when sending DELETE to server

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;
});
};
}]);

Categories