curl not connecting, but I can visit it in my browser? - ruby-on-rails

I am unsure what this is, but when I do:
curl -X POST -d '{"foo":"bar"}'
-H 'Content-Type: application/json'
-H 'Authorization: Token bdcaf10129ba8ad968c03c6083898bf8c426f749d4e9a14d58e4ef02bfe1c217'
'http://api.site.local.com:4000/internal/application/v1/users'
# New lines in above request are only there for readability.
curl: (7) Failed to connect to api.site.local.com port 4000: Connection refused
But if I go to:
http://api.site.local.com:4000/internal/application/v1/users
It works, I mean I get an error that there is no index action, but none the less the actual route exists and is working.
So why is the browser saying yes, but curl is saying no?
I mean my test:
it "should return 200 for a user being published" do
VCR.use_cassette 'publisher/publish_user_200' do
site = double(
'site',
:site_api_url => YAML.load(File.read('config/application.yml'))['APPLICATION_URL'].to_s,
:site_api_key => YAML.load(File.read('config/application.yml'))['APPLICATION_KEY'].to_s
)
expect(
BlackBird::PublishToSites::User.publish(
site,
{
first_name: 'adsadsad', user_name: 'sasdasdasdsa' ,
email: 'asdassad#sample.com', auth_token: 'asdsadasdasdsa'
}
).code
).to eql 200
end
returns a 0, meaning it could not connect. Am I doing something wrong I don't know about?
Note: The application key and url from the applications.yml file are the same as the values in the curl request.

Related

Proper forming of API requests

The following command in the console:
curl 'https://3b803ce956aa.ngrok.io/api/v1/send' -i --header "Accept: application/json" --header "Content-Type: application/json" -H 'Accept-Charset: utf-8' -H 'Authorization: Token token="GeUPm5xoxQFXR0ijJOZ6W6xr2ME1wZUWiaB3PLg9uZ8uGhFFDE7YnqCjFQwcCs0zgbtHjIiuc2jxo4I5"' -d '{"server_id":1,"building_id":1}'
but also with a version
--data '{"server_id":1,"building_id":1}'
is being received by the API controller. The routes are defined as:
namespace :api do
namespace :v1 do
post 'send', to: 'messages#send', defaults: { format: :json }
However, the handling of the requests is failing, in both cases, as it receives and returns:
Processing by Api::V1::MessagesController#send as JSON
Parameters: {"server_id"=>1, "building_id"=>1, "message"=>{"server_id"=>1, "building_id"=>1}}
Completed 500 Internal Server Error in 0ms (ActiveRecord: 0.0ms)
ArgumentError (wrong number of arguments (given 1, expected 0)):
where the controller action
def send
#request = JSON.parse(request.body.read)
#messagelog = Messagelog.create(server_id: params[:server_id], building_id: params[:building_id]
[...]
Two oddities appear:
the fact that the parameters are repeated with the contents of the parameters as part of the message
the action expects 0 arguments
I do not understand why the parameters get interpreted twice (this is a sub-question..). How can the API controller action be construed to accept the parameters?
By default Rails wraps JSON request parameters into a hash guessing its name from controller class. You can read details here.
So if you don't need this "guessed" hash in your params just remove :json from :format array in config\initializers\wrap_parameters.rb. Or you can use fine-grained control at the controller level as described above.

No route matches?

I'm getting a "No route matches" exception in one of my tests (and using curl from the command line) one of my routes (POST /users/confirm). The curl's I've tried are as follows, neither of them work and receive the same exceptions outlined in the below notes:
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ user: { "token":"1deb36b4e6a7ba6d9203" } }' \
http://localhost:3000/appname/users/confirm
curl -X POST -H "Content-Type: application/json; version=1" \
-d '{ "token":"1deb36b4e6a7ba6d9203" }' \
http://localhost:3000/appname/users/confirm
My test is as follows. I have config.wrap_parameters = true in my /config/application.rb file...
Here is my User UsersController#confirm action along with my strong params. I params.require(:user).permit(:token) as opposed to simply params.permit(:token) because, as stated above, I have config.wrap_parameters = true in my /config/application.rb file...
This is my route entry...
Here is the output from rails routes (app name removed)...
I have config.wrap_parameters = true in my /config/application.rb file...
Oddly enough, if I change my params in my test to post :confirm, params: { token: #user.confirmation_token }, I get the following error instead:
At a loss. Any thoughts?
It turns out I didn't need :token in my route after all. Changed it to this, and all is well:
post '/appname/users/confirm/', to: 'users#confirm', as: 'appname_users_confirm'

Issue with JSON request - rails/faraday

I have an issue with rails and faraday when I try to receive access token which should be included in a JSON response from the external Api.
What I want to do is user authentication based on external API.
I assume that the User already has valid credentials (in this case email as username and password).
Now when he connects to my Api, I send JSON request to the external Api to verify whether this user is valid and wait for access token.
Once the access token is sent in a response, user authentication is successful and I have access to the other endpoints
This is my controller
module Api
class AuthenticationController < ApplicationController
def create
client = XXX::AuthClient.new
response = client.authenticate(
email: params[:email],
password: params[:password]
)
api_client = XXX::Client.new(response[:access_token])
if response[:access_token]
api_user = api_client.get_user()
if api_user["id"]
db_user = User.create(xxx_id: api_user["id"], xxx_access_token: response[:access_token])
end
end
render json: { access_token: db_user.access_token }
end
end
end
And this is my AuthClient service
class AuthClient
def initialize
#http_client = Faraday.new('https://auth.xxx.com/')
end
def authenticate(email:, password:)
headers = {
'Content-Type': 'application/json'
}.to_json
body = {
grant_type: "password",
username: email,
password: password,
client_id: "particularclientid",
client_secret: "particularclientsecret"
}.to_json
api_response = http_client.post("/oauth2/token", body)
response = JSON.parse(api_response.body)
if response["access_token"]
{ access_token: access_token }
else
{ error: "autentication error" }
end
end
private
attr_reader :http_client
end
end
What I know is that curl in the following format is correct and I can see User's access token, refresh token etc.
curl -X POST -H "Content-Type: application/json" -d '{
"grant_type": "password",
"username": "test+user#example.com",
"password": "examplepassword",
"client_id": "particularclientid",
"client_secret": "particularclientsecret"
}' "https://auth.xxx.com/oauth2/token"
But when I run my curl
curl -X POST -d 'email=test+user#example.com&password=examplepassword' "http://localhost:3000/api/auth"
I see that my request is not correct. But I have no clue where is the problem because header and body are formatted to JSON (I have entered puts headers, puts body and puts response to verify that).
Started POST "/api/auth" for 127.0.0.1 at 2017-03-31 16:42:26 +0200
Processing by Api::AuthenticationController#create as */*
Parameters: {"email"=>"test user#example.com", "password"=>"[FILTERED]"}
{"Content-Type":"application/json"}
{"grant_type":"password","username":"test user#example.com","password":"examplepassword","client_id":"particularclientid","client_secret":"particularclientsecret"}
{"error"=>"invalid_request", "error_description"=>"The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
Completed 500 Internal Server Error in 610ms (ActiveRecord: 0.0ms)
NoMethodError (undefined method `access_token' for nil:NilClass):
app/controllers/api/authentication_controller.rb:21:in `create'
Is my request incorrect or the problem exists somewhere else?
I am not experienced developer. Just trying to learn enough to start as a Junior RoR. I tried to find a solution on stack and on different sites but I am stucked. Even faraday docs does not help me much
When URIs are escaped, a + is used as a replacement for whitespace. As such, when your controller un-escapes the URI, the + is changed back into a space. If you want to send a space, use %2B instead.
For your first problem, the error message indicates that db_user is nil when you try to do db_user.access_token. So, either response[:access_token] is nil, api_user["id"] is nil, or User.create failed.
You'll need to put in some debugging to find out where your problem is.

Error occurred while parsing request parameters JSON::ParserError - 795: unexpected token at

I am trying to write the API methods for user to sign up on spree app. It's working properly on my local machine but not on server. here is my code of user_decorator_controller.rb
def sign_up
#user = Spree::User.find_by_email(params[:user][:email])
if #user.present?
render "spree/api/users/user_exists", :status => 401 and return
end
#user = Spree::User.new(user_params)
if !#user.save
unauthorized
return
end
#user.generate_spree_api_key!
end
and sign_up.v1.rabl is
object #user
attributes :id, :spree_api_key, :email, :firstname, :lastname, :mobile
child(:bill_address => :bill_address) do
extends "spree/api/addresses/show"
end
child(:ship_address => :ship_address) do
extends "spree/api/addresses/show"
end
when I CURL the server with below request
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST -d {"user":{"email":"ml5698#gmail.com","password":"12345678", "firstname":"M", "lastname":"L", "mobile":"9999888877"}} http://localhost:3000/api/users/sign_up
It gives me above error below is extracts from web server log
Started POST "/api/users/sign_up" for 127.0.0.1 at 2015-10-15 11:23:36 +0530
ActiveRecord::SchemaMigration Load (0.3ms) SELECT `schema_migrations`.* FROM `schema_migrations`
Error occurred while parsing request parameters.
Contents:
{user:{email:ml5698#gmail.com,password:12345678,
JSON::ParserError - 795: unexpected token at '{user:{email:ml5698#gmail.com,password:12345678,':
json (1.8.3) lib/json/common.rb:155:in `parse'
activesupport (4.2.4) lib/active_support/json/decoding.rb:26:in `decode'
I am using Ruby 2.2 , rails 4, json 1.8.3 , what could be the issue, please help me resolve it.
Your error is actually in your use of your command line curl. You use the -d switch, and pass parameters to it. The parameters are only parsed until the next space, so your parameters being passed in are
{user:{email:ml5698#gmail.com,password:12345678,
This is what you're seeing in the error message, and is obviously not well formed JSON, so you get the parsing error.
Try quoting your -d parameters like so:
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST -d '{"user":{"email":"ml5698#gmail.com","password":"12345678","firstname":"M","lastname":"L","mobile":"9999888877"}}' http://localhost:3000/api/users/sign_up

How to test REST API request (rails)

I have REST API, for example: I already create REST users, for creating user end point is go to "localhost:3000/users" POST method.
So pattern of param should be like this :
:user => {:name => "apple", :address => "heaven"}
My question is :
How to create pattern above, then I test it to endpoint POST method ?
I already test with postman client, but failed because my pattern incorrect (miss root : user)
Thanks
A controller test will catch the type of error you're describing, and is more efficient than an end-to-end test. Example in RSpec:
it 'creates a new user' do
post :create, user: {name: 'apple', address: 'heaven'}, format: 'json'
assert_response :success
expect(response).to render_template(:create)
expect(assigns(:user).name).to eq('apple')
expect(assigns(:user).address).to eq('heaven')
end
I have used curl (in code) to test APIs end-to-end. The Faraday gem would probably work as well.
With the curl request, you'll need to pass the -X POST parameter and a -d parameter for the data. -d can have the following formats:
-d "user[name]=apple" -d "user[address]=heaven"
-d {"user": {"name": "apple", "address": "heaven"}}
You can also pass headers with -H.
Altogether:
curl http://your_url -X POST -H "Content-type: application/json" -d {"user": {"name": "apple", "address": "heaven"}}

Resources