Problem when trying to stub API requests on Rails - ruby-on-rails

I'm trying to stub an API request using Webmock. Instead of getting the "real" data from my Rails controller, I want to return dummy data, for test purposes only.
I have a React frontend with a button that fetches my api endpoint:
const handleClick = async () => {
const response = await fetch("api_endpoint");
const data = await response.json();
console.log("data: ", JSON.stringify(data));
};
This is my test file:
require 'rails_helper'
require 'spec_helper'
RSpec.describe 'visiting the embedded app', type: :system do
it 'visits the embedded app' do
stub_request(:get, 'api_endpoint').to_return(
body: { data: 'dummy' }.to_json
)
visit 'my react page with the button'
click_button "Call API"
sleep 10
random_assert
end
end
Instead of getting data: dummy, I get the "real" data from by rails controller.
What is wrong with this implementation? Tell me if you need more information!

You have fundamentially missunderstood how HTTP stubbing in tests works. WebMock is used to stub HTTP requests sent from your server to other servers.
I'm assuming this is WebMock but the same applies to pretty much any other server side HTTP stubbing tool.
It does not stub requests sent from the client - simply becuase this code isn't even running in the client. That is done with javascript libraries like Mirage JS running in the client or by sending the requests to endpoints on the server that return dummy data instead of the actual implementation.

Related

Rails Minitest for API connection

A rails action calls an API to get some data and is handled via this method:
response_osm = Geocoder::Lookup.get([...]
results = JSON.parse(response_osm)
A number of further methods can be triggered based on this data.
geometry = results['results'][0]['geometry']
zone_calc = point_in_polygon(shop.id, geometry['lng'], geometry['lat'])
The test, using a GET request will complain with WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled and provide a suggested stub stub_request(:get, [...] with( headers: { [...] }).
to_return(status: 200, body: "", headers: {})
Having actual API responses in hand, one could assert changes based on the response_osm hash.
{"documentation"=>"https://example.com/api", "licenses"=>[{"name"=>"see attribution guide", "url"=>" [...]
Inserting the quote-escaped hash as the attribute for body: "" in the stub
does not trigger any Minitest error, but also does not process subsequent steps as evidenced by a number of data captures via puts commands.
I recognize that I may be tripping myself up between stubs and mock at this point
How can this test actual work with real response data?

proper way to consume local endpoint from another controller in Rails app

I'm working on a soon to be legacy Rails App and I need to consume a local endpoint.
What I need to do is something like this
controller A
response = restClient.call("some other local endpoint belong to controller B")
do some formatting on the response
return formatted response to client
What I'm doing now is using Faraday lib for rest call:
conn = Faraday.new(
url: 'http://127.0.0.1:3000',
params: orig_params,
headers: { 'Content-Type' => 'application/json' }
)
response = conn.post('/api/v2/points/adjust')
format_response(response)
Is there a better way of doing so? what I was aiming for is like in a controller test
POST/GET like methods that 'knows' how to reach the local endpoint...
conceptually something like:
response = post('/api/v2/points/adjust')
format_response(response)
And yes, its very bad design but that is the constraint(as I mentioned it's a soon to be legacy app) I need to live with and the only questions what would be the best way to do it.

Rails - Slack API OAuth Access - invalid_client_id

I'm building Slack integration for my Ruby on Rails application and I'm trying to get an access_token from the Slack API for my Slack App when a user clicks the Add to Slack button.
From Postman, I can successfully post the following:
https://slack.com/api/oauth.access?client_id=idgoes.here&client_secret=secretgoeshere&code=12345&pretty=1
However, within Rails I always get a response with invalid_client_id, regardless of the way I call the API. I have checked my ID is correct (a lot) and tried regenerating it, but I don't think that is the issue due to the postman success.
Within my get_oauth_access_token method I have tried the following implementations:
1.
rc = JSON.parse(HTTP.post('https://slack.com/api/oauth.access',
params: {
client_id: 'idgoes.here',
client_secret: 'secretgoeshere',
code: '12345'
}))
2.
response = Excon.post('https://slack.com/api/oauth.access',
headers: { 'Content-Type' => 'application/json; charset=utf-8' },
user: client_id, password: client_secret,
body: oauth_request_body.to_json)
Any implementation I try always ends up getting a invalid_client_id response.
I'm aware it may be something to do with environment config, but I'm not sure what would be helpful to debug, so please let me know what other information I can share. I'm running on localhost.
Update:
I just found out that many (maybe all) of the Slack APIs do not accept a JSON format body (which seems crazy seeing as they send a response in JSON.
Make sure to use x-www-form-urlencoded format body on your request or it will not work properly.
"Content-Type" => "application/x-www-form-urlencoded"
I use oauth2 gem to authorize. So I was able to get this to work by reading the slack documentation and using oauth2 in my controller:
class OauthController < ApplicationController
def authorize
options = {
site: 'https://slack.com/oauth/authorize'
}
client ||= OAuth2::Client.new(
'client-id',
'client-secret',
options
)
params = {
scope: 'incoming-webhook, commands',
redirect_uri: 'https://localhost:3000/oauth/callback'
}
redirect_to client.auth_code.authorize_url(params)
end
def authorize_callback
puts params["code"]
redirect_to root_url
end
end
Routes file:
get '/authorize', to: 'oauth#authorize'
get '/oauth/callback', to: 'oauth#authorize_callback'
Don't forget to set your callback url at Oauth settings on api.slack.com, I used localhost for testing purposes as you can see.

Any way to debug RSpec request specs?

I am writing a test for a Rails API in RSpec and the endpoint has token authentication set up. I need to pass an Authorization header in the request, but I keep getting a 401 unauthorized error. Is there any way to debug and get some insight into actually which headers are being passed etc. from these types of specs? Otherwise it seems like shooting in the dark. I should note that the token provided below is working perfectly in Postman.
describe "Chirps API" do
it "GET /chirps should return 200" do
get "/chirps", headers: {
"Authorization": "Token token=7cc9f851ea0e4013b7b15ec9131f6d58"
}
expect(response).to have_http_status(200)
end
end
Assuming your controller action is chirps as well, this will help you see the complete request object
def chirps
Rails.logger.info(request.env) # complete request object
Rails.logger.info(request.headers) #just the headers
...
end
To be more interactive you can insert a byebug, then issue the command.
it { byebug }
Then enter your get in the console.

Writing Mock RSpec

I have code in my Ruby on rails project as follows, to get HTTP response from non rails API
app/model/rest_api.rb
require "uri"
require "net/https"
require "net/http"
require "active_support"
class RestApi
# the URL for the Twitter Trends endpoint
#url = 'http://api.twitter.com/1/trends.json'
def self.sampleRes
uri = URI.parse( #url)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
return response
end
end
I have just started learning Ruby on Rails and RSPEC. Can someone please help that how can I write RSpec for HTTP request without actually making request to actual API URL(need some mock)
You can mock out the request part and make expectations about what should be called etc.
mock_req = double("http request")
mock_req.should_receive(:request)
Net::HTTP::Get.should_receive(:new).and_return(mock_req)
Your code could also be simplified to:
open('http://api.twitter.com/1/trends.json').read
You aren't doing any error handling, status checking etc. (maybe this is example code?) but, whatever you expect your request to return you should mock/stub out those expectations.

Resources