Ruby - Handle incoming HTTP POST? - ruby

I seem to be missing something basic, as I don't know how to capture and then handle an incoming HTTP Post. I'm a C/C++ developer learning Ruby for the first time, and I've never dealt with web-stuff in my life.
I'm writing my first Slack Webhook, and slack will send data similar to this to my webserver:
token=ZLAmT1sKurm2KwvmYDR9hbiV
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
user_id=U2147483697
user_name=Steve
command=/weather
text=94070
response_url=https://hooks.slack.com/commands/1234/5678
I have no idea how to accept this POST request, and send it to my application for processing.
I assume it's similar to handling argv and argc for a terminal application, but I'm stuck writing the first few lines.
I've searched for a solution, but it seems like I'm asking the wrong questions.
I currently have a Puma/Sinatra webserver running on heroku, with the Procfile containing:
web: bundle exec puma -p $PORT (I also have no idea what port is assigned to it.)

Similar to this answer, Sinatra provides a DSL to accept POST requests. Within the block, the data will be accessible in the params hash. Something like
post '/my_endpoint' do
content_type :json
#team_id = params[:team_id]
res = do_stuff_with_channel_id params[:channel_id] # passing the value to a custom method example
{my_response: res}.to_json #simple example of returning JSON in response
end
Sinatra Docs on routing
HTH

Related

How to read data sent by HTTParty in Sinatra

I am trying to have two separate Ruby programs to communicate, one with the Sinatra gem, and another with the HTTParty gem. What I am attempting to do is post data to the Sinatra program from a HTTP post request in the other program.
This is the code that sends the data.
HTTParty.post('https://notgivingawaymydomain/post_data', {something: foo})
However, I don't know how to receive the data on the other end. I've tried a few things I researched on the internet but none seem to work.
EDIT
My code on the other end is really nothing special at the moment, but I'll put what I've been trying.
post '/post_data' do
#not sure how to access the hash that my post request sent here
end
The post data is available in the params object inside your Sinatra route:
post '/post_data' do
data = params["something"] # => my_value is now 'foo' in this example
#... rest of code
end
Sinatra only parses the data if it is application/x-www-form-urlencoded (which it is in this case) or multipart/form-data. If you wanted to POST another type (e.g. JSON) you would need to parse the request body yourself using request.body:
post '/json_data'
# request.body is an IO object
data = JSON.parse(request.body.read)
end
Be sure to get the syntax of your HTTParty call correct. You need to specify the body: key of the options:
HTTParty.post('http://localhost:4567/post_data', body: {something: "foo"})
if you want to post data via HTTP you need a web-server on the receiving end.
sinatra describes itself as Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort
so in itself it is not a webserver, but it can be run through a webserver to process the data that you post via HTTP. it is bundled with a webserver, so you can start it right away.
if you look at the sinatra README it says
It is recommended to also run gem install thin, which Sinatra will pick up if available.
thin is a reliable webserver that is recommended to run sinatra web applications.

about Sinatra on multiple Resources

Sorry to ask such a simple question but I didn't see any possible answer in internet.
I just wondering in Sinatra, can I write something like:
get '/users/:user_id/posts/:id' do
xxx
end
just like rails? cause when I write this on my rb file, sinatra keep telling me it didn't know this ditty.
thank you
A (horrible) example from one of our legacy systems.
get '/is_type/:type/id/:id' do
store.valid_for_type?(params)
end
Multiple placeholders in a route is totally fine in Sinatra. It sounds like your config.ru is wrong, you're issuing a POST, or you're calling the wrong endpoint entirely. Can you update your post with an example of the request you are issuing?

How does an Elixir/Phoenix app know its own websocket uri?

I'm beginning to use web sockets with an Elm frontend and a Elixir/Phoenix backend. The Phoenix server needs to tell the Elm app what uri to connect to. (E.g., ws://localhost:4000/socket/websocket in the development environment, but something else in the production environment.)
I was hoping there was something the equivalent of static_url, but I can't find it. Is there?
(I know I could hardcode the possibilities, but it seems like Phoenix must already know them.)
One way, via Chris McCord, is to change this line in YourApp.Endpoint:
socket "/socket", Eecrit.UserSocket
... with this:
#socket_mount "/socket"
def socket_uri() do
ws_url = String.replace_leading(url(), "http:", "ws:")
ws_url <> #socket_mount
end
socket #socket_mount, Eecrit.UserSocket
Note that this requires the client to add the transport /websocket to the end of the URI.
I really figured there'd be a helper function in Phoenix.Endpoint for this, but I didn't find anything.
There's likely a better solution, but my quick-and-dirty response would be to examine the conn argument that is passed into any Phoenix controller. It has a bunch of useful fields, like host and port, and a list of request headers (like host, from which you could build the websocket URL.

What is rack? can I use it build web apps with Ruby?

ruby newbie alert! (hey that rhymes :))
I have read the official definition but still come up empty handed. What exactly is it when they say middleware? Is the purpose using ruby with https?
the smallish tutorial at patnaik's blog makes things clearer but how do I do something with it on localhost? I have ruby 1.9.2 installed along with rack gem and mongrel server.
Do I start mongrel first? How?
Just to add a simplistic explanation of Rack (as I feel that is missing):
Rack is basically a way in which a web app can communicate with a web server. The communication goes like this:
The web server tells the app about the environment - this contains mainly what the user sent in as his request - the url, the headers, whether it's a GET or a POST, etc.
The web app responds with three things:
the status code which will be something like 200 when everything went OK and above 400 when something went wrong.
the headers which is information web browsers can use like information on how long to hold on to the webpage in their cache and other stuff.
the body which is the actual webpage you see in the browser.
These two steps more or less can define the whole process by which web apps work.
So a very simple Rack app could look like this:
class MyApp
def call(environment) # this method has to be named call
[200, # the status code
{"Content-Type" => "text/plain", "Content-length" => "11" }, # headers
["Hello world"]] # the body
end
end
# presuming you have rack & webrick
if $0 == __FILE__
require 'rack'
Rack::Handler::WEBrick.run MyApp.new
end
You would do well to search for other questions & answers that make sense to you. Try "Getting Started with Rails" or "Ruby Web Development". A lot of different topics on this site have been devoted to this exact subject, so you might save yourself some trouble there...
Ignoring the specifics of your question for a minute, it seems like you want to learn Ruby and build web apps. Before you start delving into Rack or Mongrel or anything else, you should know that there are 2 well established frameworks that help build Ruby web applications. The first is Ruby on Rails, and the other is Sinatra. There are many others, but these are the most well documented on Stack Overflow and the internet in general.
Check out the following links for some background...
www.rubyonrails.org
SO: building-a-website-best-practice-and-architecture-with-ruby
www.railstutorial.org
SO: learning-ruby-on-rails
If you still have a burning desire to answer your question - "what is rack?", you should follow the same process, and end up at this Stack Overflow Answer:
What is Rack middleware?
Good luck!
Very nice answers yes indeed. For my two cents I'll add this because if you know how to get to the documentation behind the scenes here you will find lots of information as I have it stashed here and by no means is all that I have.
http://myrackapps.herokuapp.com/

Ruby Oauth File upload/Multipart POST request

I've been looking at this for a couple of days now and haven't
found a solution. Is there a way to upload a file using OAuth-Ruby?
I am working with a REST system that protects their resource with oauth. I am building a test tool using ruby and oauth-ruby to make it easier to upload test data to the system. But I can't get around to upload files to the resources.
When I send a normal request, everything works but adding a file as a
parameter makes the signature invalid.
Example:
#access_token.post("http://.../imageresource", {:name=>"awesome cat"}, {'Content-Type' => 'multipart/form-data'})
works but gives me:
<error>
<message>images/POST: Request has no file data</message>
</error>
I am not sure how to add a file to the post.
Any thoughts on this?
Thanks,
I know this is old but I'm looking to do this too, this looks like it could do the trick.
Actually there's a question ruby-how-to-post-a-file-via-http-as-multipart-form-data that has an example.
This is either impossible to do with the oauth gem or exceedingly difficult. Either way, I don't know of any way to do it using that gem.
It can be done trivially with my signet gem as long as you have a handy way to construct a valid multipart request body. The construction of such a request body is out-of-scope of an OAuth gem, but should be pretty easy to do with most HTTP clients. The httpadapter gem can then translate the request into a form that signet can sign. Let me know if your preferred HTTP client isn't supported by httpadapter and I'll get that resolved immediately.
See the second example on the fetch_protected_resource method to get an idea for how this might be done.

Resources