I would like to write a REST API that return HTTP 400 when I try to create an already existing entity or when I try to update an non existing entity.
#Post
fun create(#Body entity: #Valid Entity): HttpResponse<Entity> {
val optional = entityService.find(entity)
if(optional.isPresent) {
return HttpResponse.badRequest()
}
return HttpResponse.created(entityService.save(entity))
}
How can I do that using non blocking endpoint with RXJava2 and Micronaut, I can only find examples with switchIfEmpty
#Post
#Status(HttpStatus.CREATED)
fun createMeal(#Body entity: #Valid Entity): Single<Entity> {
return entityService.find(entity)
.switchIfEmpty(entityService.save(entity))
.map{success -> entity}
}
but this code always return HTTP 200 even if nothing is saved, I don't think it's a good practice.
Thanks
You would use map to convert the entity to a bad request response since if it exists that is what you want to return. You could also use switchIfEmpty to save the entity which would only occur if the entity is not found. Ensure you wrap that code inside Flowable.defer to prevent the logic from executing no matter what. In your reactive example above the save will occur on every execution.
return entityService.find(entity)
.map(entity -> HttpResponse.badRequest())
.switchIfEmpty(Flowable.defer() -> {
//return a publisher that emits HttpResponse.created(entity)
})
Finally I do something like this :
fun update(name: String, entity: Entity): Single<Entity> {
val observable = BehaviorSubject.create<Entity>()
entitysRepository.find(name)
.subscribe(
{
entity.name = name
update(entity, observable)
},
{ observable.onError(RuntimeException("Entity : $name doesn't exist")) }
)
return observable.singleOrError()
}
fun save(entity: Entity): Single<Entity> {
val observable = BehaviorSubject.create<Entity>()
entitysRepository.find(entity.name)
.subscribe(
{ observable.onError(RuntimeException("Entity : ${entity.name} already exist")) },
{ save(entity, observable) }
)
return observable.singleOrError()
}
Don't really know if it's a good practice or not.
Related
I am unable to get values filled in the map after making a web client call and using the response of the previous Mono.Here is the code I have tried.The value of parameters.size() comes out to zero.Not able to get the reason as to why the value is not filled.I basically want to return age ( and not Mono object)
from this method.Using block gives an error block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3.
Map<String, String> parameters = new HashMap<String,String>();
Mono<Person> obj = webClient
.post()
.uri("dummy url")
.accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
.retrieve()
.bodyToMono(Person.class)
.flatMap(resp -> {
parameters.put("name", resp.getName());
parameters.put("age", resp.getAge());
return Mono.just(new Person(resp.getName(),resp.getAge()));
}
);
System.out.println(parameters.size());
Please suggest where I am wrong and solution to fix the same.
Since this is about collecting and using a token of some sort collected from a previous HTTP call, your best bet is to delegate all that to an ExchangeFilterFunction.
An ExchangeFilterFunction is a filter that is executed on the client side for each outgoing request. Here is a very, very naïve implementation of such a filter:
class TokenFilterFunction implements ExchangeFilterFunction {
private final AtomicReference<String> token = new AtomicReference<>();
#Override
public Mono<ClientResponse> filter(ClientRequest req, ExchangeFunction next) {
if (this.token.get() == null) {
return fetchToken(next).then(sendRequest(req, next));
}
else {
return sendRequest(req, next);
}
}
private Mono<ClientResponse> sendRequest(ClientRequest req, ExchangeFunction next) {
ClientRequest request = ClientRequest.from(req)
.header("Token", this.token.get()).build();
return next.exchange(request);
}
private Mono<Void> fetchToken(ExchangeFunction next) {
ClientRequest tokenRequest = ClientRequest.create(HttpMethod.GET,
URI.create("https://example.com/token")).build();
return next.exchange(tokenRequest).doOnNext(res -> {
this.token.set(res.headers().header("Token").get(0));
}).then();
}
}
This could automatically call the token endpoint to fetch a token when needed and directly chain with the request you asked in the first place. Again, such an implementation should be much more complex than that, handling domains, errors, and more.
If you're using some authentication technology, such a filter might be implemented already in Spring Security in a much, much better way.
You can configure it on your client during the building phase, like:
WebClient webClient = WebClient.builder().filter(new TokenFilterFunction()).build();
I'm trying to make a general method for sending SOAP requests and getting responses. I'm programming using Groovy and I'm using the wslite library to help me out with SOAP. Here's a sample snippet for making a SOAP request and getting a response:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
SOAPClient client = new SOAPClient('http://www.dneonline.com/calculator.asmx')
def response = client.send(SOAPAction: 'http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
}
}
By general, I meant being able to dynamically create a SOAP request (given certain information such as the service/method name, the parameters contained in the method, etc.) and obtain the SOAP response. I'm thinking something like this:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
def getResponse(String clientURL, String action, String service, String serviceNamespace, Map parameters, ...) {
SOAPClient client = new SOAPClient(clientURL)
def response = client.send(SOAPAction: action) {
body {
"$service"(xmlns: serviceNameSpace) {
...
}
}
}
}
My problem lies in constructing the closure for the request body. Like, in example, if my method received a service Add, a serviceNamespace http://tempuri.org/, and a parameter map like so: [intA: x, intB: y]... how do I merge all of these so that I can construct this kind of closure:
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
I'm pretty much a newbie to Groovy, so don't be too harsh. If there's a better way to implement this concept of a general method, I would gladly like to hear it. The concept is similar to this. But I'd rather play with Map than a String. I'm not using Grails, really. Just plain Groovy.
In short, cfrick is correct:
[intA: x, intB: y].each{fn,arg -> delegate."$fn"(arg) }
How does it work?
An easy way to see how this works is to simulate it with a fake client class:
groovy.util.NodeBuilder
class Client {
def send(String action, Closure closure) {
closure.delegate = new NodeBuilder()
closure()
}
}
def client = new Client()
def response = client.send('http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(1)
intB(2)
}
}
}
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
In the example above, the response object is created by Groovy's NodeBuilder. It's just a quick way to prototype something that processes the closure passed to Client.send().
With this testable code I'll try what cfrick suggested and validate that it works:
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body {
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
}
response = doIt('http://tempuri.org/Add', 'Add', 'http://tempuri.org/', [intA: 1, intB: 2])
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
Request Body
In addition, you can factor out the process of creating the request body:
def getRequestBody(String service, String serviceNamespace, Map params) {
{ ->
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body(getRequestBody(service, serviceNamespace, params))
}
}
I am having trouble in validating and reseting some fields based on the role of a user.
I am trying to develop a rest api with grails and my problem appears when i try to reset some fields based on the role of an user. I send a json with the desired "not allowed" changes via PUT to the controller. I modify the not allowed fields to ones that are correct for me and then call .save() and the "not alowed" fields are updated with their sent value, not with the modified by me values. Here is the code.
THE MODEL
package phonebook
class User {
String firstName
String lastName
String phoneNo
String address
String email
String password
boolean active = false
String hash
String authToken = ""
String role = "user"
static hasMany = [contacts:Contact]
static constraints = {
firstName(blank: false)
lastName(blank: false)
address(blank: true)
phoneNo(unique: true)
email(blank: false, unique: true)
password(blank: false)
role(blank: false, inList: ["user", "admin"])
hash(blank: true)
authToken(blank: true)
active(inList:[true,false])
}
}
THE METHOD FROM CONTROLLER:
#Transactional
def update(User userInstance) {
if (!isAuthenticated()){
notAllowed()
return
}
if (userInstance == null) {
notFound()
return
}
//if(isAdmin()){
def userBackup = User.findById(userInstance.id)
userInstance.role = userBackup.role
userInstance.active = userBackup.active
userInstance.hash = userBackup.hash
userInstance.authToken = userBackup.authToken
//}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'edit'
return
}
userInstance.save flush:false
request.withFormat {
'*'{ respond userInstance, [status: OK] }
}
}
THE JSON SENT VIA PUT
{
"id":"1",
"firstName": "Modified Name 23",
"role":"admin",
"active":"true",
"hash":"asdasd"
}
The above code should not modify my values for hash or active or role even if they are sent.
Any ideas?
Thanks.
The reason your changes are being saved is because by default any changes made to a domain instance will be flushed at the end of the session. This is known as open session in view with automatic session flushing. I recommend you do some reading on some of the main issues people face with GORM.
Proper use of discard may solve your issue. Discard your instance changes before you exit your controller.
For example:
if (!isAuthenticated()){
notAllowed()
userInstance.discard()
return
}
Edit
Based on conversation in the comments this perhaps may be the way to address your issue. A combination of discard and attach.
userInstance.discard()
def userBackup = User.findById(userInstance.id)
userInstance.role = userBackup.role
userInstance.active = userBackup.active
userInstance.hash = userBackup.hash
userInstance.authToken = userBackup.authToken
userInstance.attach()
I was helped by this method.
getPersistentValue
Example
def update(ShopItem shopItemInstance) {
if (shopItemInstance == null) {
notFound()
return
}
if (!shopItemInstance.itemPhoto){
shopItemInstance.itemPhoto =
shopItemInstance.getPersistentValue("itemPhoto");
}
if (shopItemInstance.hasErrors()) {
respond shopItemInstance.errors, view:'edit'
return
}
shopItemInstance.save flush:true
redirect(action: "show", id: shopItemInstance.id)
}
In your case:
userInstance.role = userInstance.getPersistentValue("role")
userInstance.active = userInstance.getPersistentValue("active")
userInstance.hash = userInstance.getPersistentValue("hash")
userInstance.authToken = userInstance.getPersistentValue("authToken")
It's better if you'll use the command objects feature. You can bind a command object with the request payload, validate it and than find and update the domain object.
You can find more details here:
http://grails.org/doc/2.3.x/guide/theWebLayer.html#commandObjects
And off the record you shoudn't use #Transactional in your controller. You can move that code into a service.
Eq:
def update(Long id, UserCommand cmd){
// Grails will map the json object into the command object and will call the validate() method if the class is annotated with #Validatable
}
This is what the section of code looks like
get{
respondWithMediaType(MediaTypes.`application/json`){
entity(as[HttpRequest]){
obj => complete{
println(obj)
"ok"
}
}
}
}~
I can map the request to a spray.http.HttpRequest object and I can extract the uri from this object but I imagine there is an easier way to parse out the parameters in a get request than doing it manually.
For example if my get request is
http://localhost:8080/url?id=23434&age=24
I want to be able to get id and age out of this request
Actually you can do this much much better. In routing there are two directives: parameter and parameters, I guess the difference is clear, you can also use some modifiers: ! and ?. In case of !, it means that this parameter must be provided or the request is going to be rejected and ? returns an option, so you can provide a default parameter in this case. Example:
val route: Route = {
(path("search") & get) {
parameter("q"!) { query =>
....
}
}
}
val route: Route = {
(path("search") & get) {
parameters("q"!, "filter" ? "all") { (query, filter) =>
...
}
}
}
I am using Grails with RESTful to develop my web application. Everything works fine, till I upgrade my application to Grails 2.3. Here is my UrlMappings:
I still send request, submit or do some other things normally, but in POST, PUT requests, the parameters are missing. Server just recognize only the parameters I put on the URL directly, but the remain I enclose in form or model when submit cannot be found in the "params" variable. He is my UrlMappings:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{ constraints {} }
name apiSingle: "/api/$controller/$id"(parseRequest:true){
action = [GET: "show", PUT: "update", DELETE: "delete"]
constraints { id(matches:/\d+/) }
}
name apiCollection: "/api/$controller"(parseRequest:true){
action = [GET: "list", POST: "save"]
}
name api2: "/api/$controller/$action"(parseRequest:true)
name api3: "/api/$controller/$action/$id"(parseRequest:true)
"/"(view:"/welcome")
"500"(view:'/error')
}
}
I have read the latest document of Grails 2.3, at http://grails.org/doc/latest/guide/theWebLayer.html#restfulMappings
but I think it is not clear. I have tried it follow the documentation but have no result. And there are no any sample about using Grails 2.3 with RESTful for me to refer.
How can I make it work normally as before, and can access all parameter values in REST request? Thank you so much!
According to this http://grails.1312388.n4.nabble.com/Grails-2-3-and-parsing-json-td4649119.html parseRequest has no effect since Grails 2.3
If you use JSON as request body you can accees request params as request.JSON.paramName
As a workaround you can add a filter that will populate data from JSON to params:
class ParseRequestFilters {
def filters = {
remoteCalls(uri: "/remote/**") {
before = {
if (request.JSON) {
log.debug("Populating parsed json to params")
params << request.JSON
}
}
}
}
}
Adding on to Kipriz's answer and cdeszaq's comment, you can write a recursive method to inject nested params. Something along these lines:
public void processNestedKeys(Map requestMap, String key) {
if (getParameterValue(requestMap, key) instanceof JSONObject) {
String nestedPrefix = key + ".";
Map nestedMap = getParameterValue(requestMap, key)
for (Map.Entry<String, Object> entry : nestedMap.entrySet()) {
String newKey = nestedPrefix + entry.key;
requestMap.put(newKey, getParameterValue(nestedMap, entry.key))
processNestedKeys(requestMap, "${nestedPrefix + entry.key}");
}
}
}
public static Map populateParamsFromRequestJSON(def json) {
Map requestParameters = json as ConcurrentHashMap
for (Map.Entry<String, Object> entry : requestParameters.entrySet()) {
processNestedKeys(requestParameters, entry.key)
}
return requestParameters
}