I'm using GoLang and Gin Framework.
I need to respond for REST API call with 204 response code without message body.
How it is to do properly?
What I could find by digging the source code
c.JSON(204, "")
But server throws error at such case:
Error #01: http: request method or response status code does not allow body
Meta: []
Any ideas?
You could use c.AbortWithStatus(204), with the one caveat that when you use abort, the rest of pending handlers will never be called for that request.
Or, you could do:
c.Writer.WriteHeader(204)
and let your program continue normally (but making sure not to write out anything else)
adding on #depado comments,
c.Status(http.StatusNoContent) is the simplest way to achieve this.
Works with gin v1.6.3
up to now, the function Abort's prototype is
func (c *Context) Abort()
you can use AbortWithStatus instead c.AbortWithStatus(204), whose prototype is
func (c *Context) AbortWithStatus(code int)
Related
I have followed the cook books guide to the letter, found here https://echo.labstack.com/cookbook/jwt
But when using the JWT middleware I am having some issues with adding custom error messages. Login works fine, even to the point of not giving details (username & password) that returns a 404.
But when the JWT is missing it returns a 400, I want it to also return a 404.
So in my research I found this, https://forum.labstack.com/t/custom-error-message-in-jwt-middleware/325/3 which lists the following middleware.ErrJWTMissing & middleware.ErrJWTInvalid But is very unclear on how to set these?
I have tried setting them as vars on the router file, like so
var (
ErrJWTInvalid = echo.NewHTTPError(http.StatusTeapot, "test 104")
ErrJWTMissing = echo.NewHTTPError(http.StatusTeapot, "test 103")
)
But the error that sill comes back to me is a 400 and not a 418 (as this is just a test). So what am I doing wrong?
You can change the HTTP code and message this way.
func init() {
middleware.ErrJWTMissing.Code = 401
middleware.ErrJWTMissing.Message = "Unauthorized"
}
First, a point on your statement that you want to return a 400 and also a 404 error - you cannot do this. You're sending one response from the server so it gets exactly one response code. You could send a 207, but we're not really talking about multiple resources here, so don't do that. In my opinion, a 400 error is indeed the correct response for a missing JWT as that constitutes a bad request. A 404 "Not Found" means that the requested resource (the thing on the server side) could not be found. It does not mean that something in the request could not be found.
As for setting your custom error message, you're likely to be out of luck without altering the source code for Echo. That specific response is coming from within the middleware handlers of the package itself (you can see it here). This is mostly abstracted away from you, so without looking at the inner workings of the package, there would be no way to tell where this was coming from, and frankly there's not a lot that you can easily do about it. ErrJWTMissing is indeed the variable that the package uses internally for this error message, but Echo does not appear to provide an exported setter method for you to change this value, so you're stuck with what it is.
If you truly wanted to set a custom error method for this case I think your options would be to:
Write your own middleware to intercept the request before it was handled by Echo's middleware, where you could handle the request however you wanted.
Edit the Echo source to work how you wanted it to work -- specifically, all you would have to do is edit ErrJWTMissing.
Basically, Echo is trying to do you favors by handling all of this middleware processing for you, and it's a lot of work or hackery to un-do that work while still using Echo.
I've been attempting to inject a custom header for a error response status (and failing).
I have a very simple lambda being used
exports.handler = (event, context, callback) => {
// TODO implement
//callback(null, 'Hello from Lambda');
var error = {
name:"error",
message:"I am a failure",
statusCode: 400
};
error["x-test"] = 'foo';
callback(JSON.stringify(error), null);
};
In the api gateway, I've done the following:
set up CORS to include x-test
responsetemplate = "$input.path('$.errorMessage')"
responseparameter to include:
method.response.header.x-test = integration.response.body.x-test
Also, I have a statusCode mapped using '.*statusCode.*?400.*'
This has turned out empty.
so I decided to take a step back and see what happens if I do:
method.response.header.x-test = integration.response.body
I found that I get the stringified response of errorMessage.
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
So I decided to change the responsetemplate to force it to json by doing the following:
responsetemplate = "$util.parseJson($input.path('$.errorMessage'))"
and I still get the stringified response:
{"x-test":"{\"errorMessage\":\"{\\\"name\\\":\\\"error\\\",\\\"message\\\":\\\"I am a failure\\\",\\\"statusCode\\\":400,\\\"x-test\\\":\\\"foo\\\"}\"}"}
My guess is that it doesn't transform as expected, but only for the final output.
So how would you take a value and shove it into a header?
Thanks,
Kelly
I think this is more of a design choice regarding the limitation imposed by both Lambda and APIGateway. I will try my best to walk through my thoughts.
First of all, in Lambda, callback(error, result) function can either take an error string as first argument, or an object as result response. If you want to pass along a simple error message, you could definitely just do that. However, in your case, as you tried to pass along an entire error object, choosing the second option is clearly a better solution (in contrast to stringifying an object and parse it into object again). As a result, the final line of your Lambda function should be:
callback(null, error);
Yes, in this case, if you test your function in Lambda, the output result will no longer be red and flag it as an error, but this won't matter as you can format your headers and response in APIGateway.
Now you need to set things up in APIGateway, in which you need to make use of the object passed by Lambda.
It's actually rather easy to use method execution interface to configure headers.
In Method Response, you need to add the headers you want to include in the response for a specific status code, which in your case is x-test. (If you want the API to return different status codes, you can also configure that in this panel.)
Then go to Integration Response, under the same status code, you will see the added header available. According to this documentation from AWS, you can use integration.response.body.JSONPath_EXPRESSION to assign the header value (this is another reason that you should return object rather than string in Lambda, as there is no formal API to parse object from string at this stage). This time, as your Lambda is passing an object, the value of x-test header is:
integration.response.body['x-test']
Now your API should have the proper header included.
NOTE: In order to set up different status code in APIGateway, you should leave some distinguishable data fields (your statusCode: 400 should work perfectly) in you response body, so you can use RegEx to match those fields to a specific status code.
So... above doesn't work with success message. I found this blog though talking about error handling design pattern. Apparently what they suggest is only mapping status code when there is an error, in which case no body should be passed (only the errorMessage), as browser won't care about response body for a status code other than 200 anyway.
I guess after all, it is impossible to customize both status code and header at the same time with Lambda passing an object to APIGateway?
This is due to the fact that you are stringifying the error object coming from your Lambda function. API Gateway attempts to resolve the JSON-Path expression and can't evaluate "x-test" in a string. If you return an object instead of a string, this should work.
You may want to consider using proxy integrations which allow you to control the headers and status directly from your Lambda function.
Update: I've written a blog post on this topic with sample code # https://rpgreen.wordpress.com/2017/01/25/how-to-send-response-headers-for-aws-lambda-function-exceptions-in-api-gateway/
Im currently making a web app using Go. I want to know on my templates when the user is logged in or not and I am currently making it using this approach
response := &viewCharacter{true}
template.Renderer.ExecuteTemplate(w, "character_search.html", response)
As you see I am passing a viewCharacter struct that only contains a bool Logged then on a template I can do the following
{{ if .Logged }}
Is there any other approach to do this? instead of passing on each template a logged bool?
Maybe setting a variable for each goroutine of the http handler that saves if the user is logged or not?
There are only two ways that I know to communicate between the go code and the template.
The first one is the one you use. By passing a struct to the ExecuteTemplate function you can access all its field in the template.
The second one is to register other functions using:
func (t *Template) Funcs(funcMap FuncMap) *Template
See documentation for more information. The funcMap is a simple map[string]interface{}, you can register any function and call it in the template by using its name (the key of the map).
I'm writing a simple API in Spring and I'm wondering what is the cleanest way to acknowledge successful calls like updates/deletions which don't return any data with something like
{status:"ok"}
I can obviously return a String or predefined OK_Object but there surely must be better way to do it.
I would just return a 204 (no body).
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an
entity-body
see https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
I write a class to handle the request to web. And it has a method which is using WebClient actually to do the main job. When the DownloadStringCompleted method has been done, I want to return the value of the response.
I want to use that like this:
// the pubTimeLine() method returns the value
// of the request to the web using WebClient
textBlock1.DataContext = wp.pubTimeLine(url);
How to make it? Or how to get the synchronous response of HTTP request?
You should never make synchronous network calls, it will freeze up your UI (and therefore your phone) which is a very bad user experience.
Instead do it asynchronously, something like:
wp.pubTimeLine(url, result => textBlock1.DataContext = result);
Where the second parameter is a lambda expression containing the callback that is called when the pubTimeLine method is done executing asynchronously.