Grails 'grails-rest-client-builder' plugin with PATCH request method - grails-plugin

I'm using grails2.4.4 and grails-rest-client-builder: 2.0.0 plugin. I need to invoke a REST URL which accepts request method, PATCH. But i'm not able to do with this plugin:
I'm using below code:
def rest = new RestBuilder()
def resp = rest.patch("$URL") {
header 'Authorization', "Bearer $accessToken"
}
I'm getting below error:
Invalid HTTP method: PATCH. Stacktrace follows:
Message: Invalid HTTP method: PATCH
Line | Method
440 | setRequestMethod in java.net.HttpURLConnection
307 | invokeRestTemplate in grails.plugins.rest.client.RestBuilder
280 | doRequestInternal . in ''
Can anyone please help me out?

Ok. Finally made it after several trial and errors. As default java.net.HttpURLConnection doesn't support custom request method like PATCH, i'm getting that error. So i need to go for some thirdparty libraries like commons-httpclient which supports such request methods. So i injected commons-httpclient(now it is named as apache-httpcomponents) to make it work with PATCH request method.
Below are the changes i did to make it work:
First add dependency in grails BuildConfig.groovy
runtime "org.apache.httpcomponents:httpclient:4.3.6"
Solution#1
If you want to go by manual object creation:
RestTemplate restTemplate=new RestTemplate()
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
def rest=new RestBuilder(restTemplate)
def resp = rest.patch("$URL"){
header 'Authorization', "Bearer $accessToken"
}
Solution#2
Using Grails-Spring Injection:
Add below configuration in resources.groovy
import grails.plugins.rest.client.RestBuilder
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate
beans={
httpClientFactory (HttpComponentsClientHttpRequestFactory)
restTemplate (RestTemplate,ref('httpClientFactory'))
restBuilder(RestBuilder,ref('restTemplate'))
}
Inject restBuilder in your class:
class MyRestClient{
def restBuilder
....
def doPatchRequest(){
def resp=restBuilder.patch("$API_PATH/presentation/publish?id=$presentationId"){
header 'Authorization', "Bearer $accessToken"
};
//do anything with the response
}
}
Hope this helps someone.

Related

Custom general error handler for Flask API server [duplicate]

Is there a way to add a global catch-all error handler in which I can change the response to a generic JSON response?
I can't use the got_request_exception signal, as it is not allowed to modify the response (http://flask.pocoo.org/docs/0.10/signals/).
In contrast all signal handlers are executed in undefined order and do not modify any data.
I would prefer to not wrap the app.handle_exception function as that feels like internal API. I guess I'm after something like:
#app.errorhandler()
def handle_global_error(e):
return "Global error"
Note the errorhandler does not take any parameters, meaning it would catch all exceptions/status codes which does not have a specific error handler attached to them. I know I can use errorhandler(500) or errorhandler(Exception) to catch exceptions, but if I do abort(409) for example, it will still return a HTML response.
You can use #app.errorhandler(Exception):
Demo (the HTTPException check ensures that the status code is preserved):
from flask import Flask, abort, jsonify
from werkzeug.exceptions import HTTPException
app = Flask('test')
#app.errorhandler(Exception)
def handle_error(e):
code = 500
if isinstance(e, HTTPException):
code = e.code
return jsonify(error=str(e)), code
#app.route('/')
def index():
abort(409)
app.run(port=1234)
Output:
$ http get http://127.0.0.1:1234/
HTTP/1.0 409 CONFLICT
Content-Length: 31
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:54 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "409: Conflict"
}
$ http get http://127.0.0.1:1234/notfound
HTTP/1.0 404 NOT FOUND
Content-Length: 32
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:58 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "404: Not Found"
}
If you also want to override the default HTML exceptions from Flask (so that they also return JSON), add the following before app.run:
from werkzeug.exceptions import default_exceptions
for ex in default_exceptions:
app.register_error_handler(ex, handle_error)
For older Flask versions (<=0.10.1, i.e. any non-git/master version at the moment), add the following code to your application to register the HTTP errors explicitly:
from werkzeug import HTTP_STATUS_CODES
for code in HTTP_STATUS_CODES:
app.register_error_handler(code, handle_error)
This is Flask 0.12 compatible, and a very good solution to the problem (it allows one to render errors in JSON or any other format)
from functools import wraps
from flask import Flask, redirect, jsonify
app = Flask(__name__)
def get_http_exception_handler(app):
"""Overrides the default http exception handler to return JSON."""
handle_http_exception = app.handle_http_exception
#wraps(handle_http_exception)
def ret_val(exception):
exc = handle_http_exception(exception)
return jsonify({'code':exc.code, 'message':exc.description}), exc.code
return ret_val
# Override the HTTP exception handler.
app.handle_http_exception = get_http_exception_handler(app)
https://github.com/pallets/flask/issues/671#issuecomment-12746738
Far from elegant, but the following works for tying all subclasses of HTTPException to a single error handler:
from flask import jsonify
from werkzeug.exceptions import HTTPException
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for cls in HTTPException.__subclasses__():
app.register_error_handler(cls, handle_error)
A cleaner way to implement this in Flask >=0.12 would be to explicitly register the handler for every Werkzeug exception:
from flask import jsonify
from werkzeug.exceptions import HTTPException, default_exceptions
app = Flask('test')
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for exc in default_exceptions:
app.register_error_handler(exc, handle_error)
It is possible to register error handlers for very generic base classes such as HTTPException or even Exception. However, be aware that these will catch more than you might expect.
For example, an error handler for HTTPException might be useful for turning the default HTML errors pages into JSON. However, this handler will trigger for things you don’t cause directly, such as 404 and 405 errors during routing. Be sure to craft your handler carefully so you don’t lose information about the HTTP error.
from flask import Flask, abort, jsonify, json
from werkzeug.exceptions import HTTPException
app = Flask('test')
app.config['JSON_SORT_KEYS'] = False
#app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"error": {
"code": e.code,
"name": e.name,
"description": e.description,
}
})
print(response.data)
response.content_type = "application/json"
return response
#app.route('/')
def index():
abort(409)
#app.route('/aloha')
def aloha():
abort(400, "I'm not in the mood to talk!")
app.run(port=1234)
output:
An error handler for Exception might seem useful for changing how all errors, even unhandled ones, are presented to the user. However, this is similar to doing except Exception: in Python, it will capture all otherwise unhandled errors, including all HTTP status codes.
In most cases it will be safer to register handlers for more specific exceptions. Since HTTPException instances are valid WSGI responses, you could also pass them through directly.
from werkzeug.exceptions import HTTPException
#app.errorhandler(Exception)
def handle_exception(e):
# pass through HTTP errors
if isinstance(e, HTTPException):
return e
# now you're handling non-HTTP exceptions only
return render_template("500_generic.html", e=e), 500
Error handlers still respect the exception class hierarchy. If you register handlers for both HTTPException and Exception, the Exception handler will not handle HTTPException subclasses because it the HTTPException handler is more specific.
Based on
Plain (non-HTML) error pages in REST api
I wanted to return json without changing any of my code at all, so I just added the following on the top of my code
#app.errorhandler(500)
def error_500(exception):
return jsonify({"error": str(exception)}), 500, {'Content-Type': 'application/json'}
#app.errorhandler(400)
def error_400(exception):
return jsonify({"error": str(exception)}), 400, {'Content-Type': 'application/json'}
If the Exceptions doesn't work, you may try app.register_error_handler (or use app.errorhandler in a non-decorator way)
Source: https://github.com/pallets/flask/issues/1837

Advice for implementing custom authentication scheme [duplicate]

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks
Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

How to handle requests with signatures on karate tests?

First of all, thanks for build karate it's a very useful for test API's and UI's. We are using it to test a lot of our endpoints but we would like to know if there is a way or which is the best approach to handle requests with signature as part of the request in the header.
In our case we have two headers:
ApiKey: this value is always the same
Signature: this value depends on the request body content
Is there any way to inject the signature value just before the request is executed based on the request body content?
Here you can see two samples of the requests
Sample 1:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'YYY'
And request { }
When method POST
Then status 200
Sample 2:
* url 'https://dev.sample.com'
* path '/api/user/getAll'
* header Content-Type = 'application/json'
* header ApiKey = 'XXX'
* header Signature = 'ZZZ'
And request { name: 'John' }
When method POST
Then status 200
Thanks
Karate has a "hook" for generating headers, but as of now it is not "aware" of the currently built request body + headers: https://github.com/intuit/karate#configure-headers
We got a similar request here, and are thinking of adding this capability: How to retrieve raw request contents before making a REST call in Karate DSL?
Maybe the OAuth examples will give you the way forward for your case for now: https://stackoverflow.com/a/55055111/143475
Feel free to raise an enhancement request, and we can get this in to the next version (with your help to test it). I'm thinking - what if you are able to call karate.get('request') from within the header JS function.
But for now all you need to do is do something like this:
* def body = { some: 'json' }
* karate.set('requestBody', body)
* url someUrl
* request body
* method post
And in the header.js function
function fn() {
var body = karate.get('requestBody');
var sign = Utils.sign(body);
return { Signature: sign };
}
EDIT: this will be implemented in Karate 1.0 onwards: https://github.com/intuit/karate/issues/1385

TRON not using request.header

I am using Xcode 8.3.3 (8E3004b)
I am using TRON (which includes Alamofire) to make HTTP Request to my REST API.
I have been successful getting a simple API working with this setup. I am trying to connect to a different API, which requires me to set the headers. It is this API that is throwing a Status 415 server error.
I have the following code to make the request via TRON. According to the TRON Github page, I should be ae to set the header like this:
request.headers = ["Content-Type":"application/json"]
I have also tried:
request.headerBuilder.headers(forAuthorizationRequirement: AuthorizationRequirement.allowed, including: ["Content-Type":"application/json"])
I tried adding a few different ways of writing that, but nothing seems to work.
Here's a bigger section of the code so you can see the context
let urlSubfix = "\(Constant.REST_MOBILE)\(Constant.REGISTER)"
let request: APIRequest<RegisterApiResult, JSONError> = tron.request(urlSubfix)
request.method = .put
// request.headers = ["Content-Type":"application/json"]
let header = request.headerBuilder.headers(forAuthorizationRequirement: AuthorizationRequirement.allowed, including: ["Content-Type":"application/json"])
request.headers = header
request.perform(withSuccess: { (registerApiResult) in
print("Successfully fetched our json object")
completion(registerApiResult)
}) { (err) in
print("Failed to fetch json...", err)
}
Here is the actual error from my log:
Failed to fetch json... APIError<JSONError>(request: Optional(http://www.slsdist.com/eslsd5/rest/mobileservice/register), response: Optional(<NSHTTPURLResponse: 0x618000028c20> { URL: http://www.slsdist.com/eslsd5/rest/mobileservice/register } { status code: 415, headers {
"Content-Length" = 0;
Date = "Sat, 22 Jul 2017 22:23:14 GMT";
Server = "Microsoft-IIS/7.5";
"X-Powered-By" = "Undertow/1, ASP.NET";
} }), data: Optional(0 bytes), error: Optional(Alamofire.AFError.responseValidationFailed(Alamofire.AFError.ResponseValidationFailureReason.unacceptableStatusCode(415))), errorModel: Optional(Go_Cart.Service.JSONError))
As you can see I have tried to set the headers a couple different ways, but neither of them seems to take affect. Any help or advice from anyone would be helpful.
Thanks in advance.

JayData oData request with custom headers

I need to send custom headers to my wcf oData Service but with the following function the headers dont get modified.
entities.onReady(function () {
entities.prepareRequest = function(r) {
r[0].headers['APIKey'] = 'ABC';
};
entities.DataServiceClient.toArray(function (cli) {
cli.forEach(function (c) {
console.log(c.Name)
});
});
});
headers are not affected. any clue?
thanks!
It seems that the marked answer is incorrect. I was suffering from a similar issue, but got it working without changing datajs.
My issue was that I was doing a cross domain (CORS) request, but didn't explicitly allow the headers. After I added the correct CORS header to the webservice, it worked.
EDIT
On second thought, it seems like there is still something broken in JayData for MERGE requests.
This is NOT CORS and has nothing to do with it!
see JayData oData request with custom headers - ROUND 2
the bellow "hack" works, but the above question should take this problem to a new level.
----------
Old answer
Nevermind I found a solution.
It seems like prepareRequest is broken in JayData 1.3.2 (ODataProvider).
As a hack, I added an extraHeaders object in the providerConfiguration (oDataProvider.js):
this.providerConfiguration = $data.typeSystem.extend({
//Leave content unchanged and add the following:
extraHeaders: {}
}, cfg);
then at line 865 modify requestData like this:
var requestData = [
{
requestUri: this.providerConfiguration.oDataServiceHost + sql.queryText,
method: sql.method,
data: sql.postData,
headers: _.extend({
MaxDataServiceVersion: this.providerConfiguration.maxDataServiceVersion
},this.providerConfiguration.extraHeaders)
},
NOTE: Iam using lodash for conveniance, any js extend should do the trick.
then you just create your client like this:
var entities = new Entities.MyEntities({
name: 'oData',
oDataServiceHost: 'http://myhost.com/DataService.svc',
maxDataServiceVersion: "2.0",
//enableJSONP: true,
extraHeaders: {apikey:'f05d1c1e-b1b9-5a2d-2f44-da811bd50bd5', Accept:'application/json;odata=verbose'}
}
);