What is the amber equivalent of render text: 'asfasdf' (or in newer rails: render body: 'asdfasdf')? I need to render raw text as part of an API.
def text_api
"hello world!"
end
omg why didn't rails do it this way so simple!! :+1:
Yeah I love rails but this is definitely one of the things I wanted to do differently.
And don't forget response.content_type = "test/plain" or other Content-Type you need.
@c910335 is there a way I can do that in my base ApiController or do I need to do it in every single method. Also would super appreciate a JSON example?
Custom Pipe or Filters should be good for you.
Yeah. Just write a simple custom pipe to do that.
For JSON just write
def api_action
{"name" => "elorest"}.to_json
end
Also make sure to set the response type to json.
excellent, thanks all
@sam0x17 Here's an example handler/pipe you could use to set content_types for you.
class TextType
include HTTP::Handler
def call(context : HTTP::Server::Context)
content.response.content_type = "test/plain"
call_next context
end
end
@elorest thanks!
Don't know how anyone else feels about this, but for purposes of readability and ease of use it could be nice to have a similar functionality to Rails here by using the render method with a named json attribute. That way the render method could take the hash, variable, etc, apply to_json if necessary, set the content type, and render the json response.
@watzon something like this?
https://github.com/kemalyst/kemalyst/blob/master/src/kemalyst/helpers.cr#L36
@drujensen something like that would work. Did that code not get ported over when kemalyst became amber?
correct, Amber and Kemalyst had different approaches on this and it's been in discussion if we should port this more rails'ish style over or have the simpler style where you just return what you want as the body and use a handler or before filter to specify the content-type.
_[insert "why not both" gif here]_
I feel like it would be really nice to have the ease of using a helper function like that, but also have the ability to just return whatever I want. Maybe I just want to have my cake and eat it too haha.
My suggestion would be that we add them but don't require them.
class Amber::Controller::Base
protected def text(body, status_code = 200)
context.response.status_code = status_code
context.response.content_type = "text/plain"
# We need to use content instead of response.print so that we don't close down the response object before session are written, in chunking mode.
context.content = body
end
end
Then we can modify the controller proc to not set content from the return value if it's already been set.
@drujensen WDYT?
@elorest great idea.
I've began work on it. https://github.com/amberframework/amber/pull/313
For Web/REST API currently i create a class with method helper to handle http response.
Each controller api then inherits that class. It's inspired from aspnet API methods.
I set all response in json or plain text.
lass ApiController < Amber::Controller::Base
protected def response(status_code : Int32 = 200, content = "")
@context.response.status_code = status_code
@context.content = to_json(content)
end
private def to_json(content : String | NamedTuple)
if content.is_a?(NamedTuple) ?
@context.response.content_type = "application/json"
content.to_json
else
@context.response.content_type = "text/json"
content
end
end
macro ok(content = "")
return response 200, {{content}}
end
# Other macros with predefined status code for created, updated, not_found etc
end
So when i need to send plain 200 response, simply i just write ok("Success")
Others : ok(someNamedTupleFromDB), not_found("Resource not found")
Resolved with #367
Most helpful comment
My suggestion would be that we add them but don't require them.
Then we can modify the controller proc to not set content from the return value if it's already been set.
@drujensen WDYT?