I'm using HTTP::UserAgent to try and use GitHub API from a program. Here's the program
use HTTP::UserAgent;
my $greeting = (%*ENV<BODY> ~~ /[Mm]erry/)??%*ENV<GREETING>!!%*ENV<HEY>;
my $url = "https://api.github.com/repos/JJ/raku-advent-calendar-article-2019/issues/%*ENV<ISSUE>/comments";
my %headers = Authorization => "token %*ENV<TOKEN>" ;
my %payload = body => $greeting;
my $agent = HTTP::UserAgent.new( useragent => "JJ's Xmas commenter" );
say $agent.post( $url, %payload,
Authorization => "token %*ENV<TOKEN>",
Content-Type => "application/json" );
If the content-type is not established, there's a malformed JSON error. If it's used, however, the error is different: 422 Unprocessable Entity. When using curl or similar, you can usually post directly the JSON string, but post in this case does not admit single strings, or if it's a form, I have no idea what to use as key. Can you please help?
Related
I'm working with React-Native right now, trying to pass formdata to a backend php-file as JSON. But everytime the form is submitted the console shows the following error "SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data". With firefox I checked the request and response under network.
Under request it shows the JSON correctly, under response it shows the JSON correctly. 1 thing that stands out is that under Headers, it says that response Content-Type is text/html and that request Content-Type is text/plain. Could that be causing the issue? I wouldn't know what else to do since I already specify the Content-Type in the code.
Google Chrome says .then(response => response.json()) is causing the error.
await fetch('http://192.168.2.16/React-Native/endpoint.php', {
method: 'POST',
header: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify({
intensiteit: intensiteit,
soortStank: soort,
latitude: lat,
longitude: long,
buurt: neighbourhood,
}),
mode: 'no-cors',
})
.then(response => response.json())
.then(responseJson => {
Alert.alert(JSON.stringify(responseJson));
})
.catch(error => {
console.error(error);
});
The php-file:
$obj = file_get_contents('php://input');
$obj = json_decode($obj, true);
$result['soort'] = $obj['soortStank'];
echo json_encode($result);
And yes I looked at other posts, but they didn't help sadly. I also tried adding dataType: 'json', in there, but that didnt help.
The request from your front-end app to the back-end endpoint is a cross-origin request. Adding mode: 'no-cors' to the fetch request doesn't change this, so remove it to begin with.
Next, the php endpoint must include some header declarations to allow the cross-origin request to succeed.
Add the following to the top of the php file, replacing the http://localhost:9999 part with the origin you are sending the request from. When testing locally, it'll likely be identical apart from the port number. When running in production, be sure to replace it with the correct origin for your front-end app eg. https://www.example-app.com.
header("Allow-Access-Control-Origin: http://localhost:9999");
header('Content-Type: application/json');
This should work.
This is likely a problem of null values.
Replace null values with empty strings in the body.
Perhaps, you also just need to change the php file to:
$obj = file_get_contents('php://input');
$obj = json_decode($obj, true);
$result['soort'] = $obj['soortStank'] ?? '';
echo json_encode($result);
I would like to access to a website with a lot of information and display all of it (as of now). However, I want to use JSON.parse and also authenticate the user and password in order to extract that information.
This is what I have:
require 'net/http'
require 'json'
url = 'http://robotrevolution.net/interface/int_order_options.php'
uri = URI(url)
response = Net::HTTP.get(uri)
jsonVal = JSON.parse(open(response))
puts jsonVal
However, while looking up online, I found I can use this:
require 'net/http'
require 'json'
require 'uri'
uri = URI('http://robotrevolution.net/interface/int_order_options.php')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
request = Net::HTTP::Get.new uri.request_uri
request.basic_auth 'username', 'password'
response = http.request request # Net::HTTPResponse object
puts response
puts response.body
end
Moreover, I would like to find a way to mix both of them and use automatic authentication as well as parse JSON at the same time. Thank you.
Consider using RestClient library (https://github.com/rest-client/rest-client).
Example:
require 'rest-client'
require 'json'
require 'ostruct'
url_endpoint = 'https://api.example.com'
basic_auth_user = 'user'
basic_auth_password = 'pass'
basic_auth_creds = "#{basic_auth_user}:#{basic_auth_password}"
response = RestClient.get(url_endpoint, {
Authorization: "Basic #{Base64::encode64(basic_auth_creds)}"
})
json = JSON.parse(response.body, object_class: OpenStruct) unless response.empty?
I'm trying to receive a request from a webservice via JSON and send a successful response message back if the token is correct along with some other identifying information, otherwise send a proper error message
post "/hook/foo/bar" do
puts request.env
if request.env['TOKEN'] === "secret_code"
HTTParty.post("https://hook.com/hooks/catch/foo/bar/",
{
:body => #info.to_json,
:headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json'}
})
[200, {}, "Success"]
else
[400, {}, "Authorization Failed"]
end
The service sending the hook (Zapier) says it sends successfully, but i'm not responding any meaningful data to them that I can use. I believe my formatting for my responses is wrong, but i'm not sure how.
David from the Zapier Platform team here.
Per the sinatra docs, you can return:
An Array with three elements: [status (Fixnum), headers (Hash), response body (responds to #each)]
So you're sending back no hints on the content type and a string as the body. This is valid, and your hook succeeds, but you can do better!
Zapier parses the response from an outgoing hook as JSON, so it's best to send that back.
I've just tested the following example:
require 'sinatra'
require 'json'
get '/' do
'hello world!'
end
post '/hook' do
{message: 'great!'}.to_json
end
and my response was parsed!
If you want to set a status code, honestly the easiest way to do it is with the function status(400) anytime before your return. That being said, a 401 is probably the code you want for Unauthorized", rather than400`. Either way though, zapier will flag that run as an error.
Let me know if you've got any other questions!
How can I set a cookie with a json response?
I noticed, for me at least, the following command is the only thing working that sets a cookie:
return Redirect::to('/')
->withCookie(Cookie::make('blog', $cookie_values, 1000));
Of course if it was an ajax request it would return the target of the redirect.
How could I translate this to an ajax request and return a json response with the cookie?
I was able to set a cookie with a json response with the following code:
$cookie_values = array(
'name' => Input::get('name'),
'id' => Auth::user()->id,
'login_success' => 1);
if(Request::ajax())
{
$cookie = Cookie::make('blog', $cookie_values, 1000);
$response = Response::json($cookie_values);
$response->headers->setCookie($cookie);
return $response;
}
Great hint!
Having a look at Symfony\Component\HttpFoundation\ResponseHeaderBag also revealed how to set headers for a json response when having problems with HTTP access control:
$response->headers->set('Access-Control-Allow-Origin', '/* your subdomain */');
I have been playing around with using rest-client to access a rails app I have written. I've written a quick script to log in and make a post request. Everything is working but I did have to work round the fact that no authenticity_token is served if you make a request for a form in json. I had to make a regular html request in other get the authenticity_token and then included this in the json I submitted as part of my post request. Basically I have a quick an dirty script like the one below
private_resource = RestClient::Resource.new( 'https://mysite.com')
params = {:user => {:email => 'user#mysite.com', :password => 'please'}}
#log in
login_response = private_resource['users/sign_in'].post(params, :content_type => :json, :accept => :json)
#get cookie
cookie = login_response.cookies
#get json
json_response = private_resource['products/new'].get(:content_type => :json, :accept => :json, :cookies => cookie)
#another request that returns html form with authenticity token
response_with_token = private_resource['products/new'].get( :cookies => cookie)
#extract token
token = Nokogiri::XML(response_with_token).css('input[name=authenticity_token]').first.attr('value')
#update cookie
cookie = response_with_token.cookies
#populate form and insert token
form = JSON.parse(json_response)
form['name'] = "my product"
form['authenticity_token'] = token
#submit the request
private_resource['products'].post(form.to_json, {:cookies => cookie, :content_type => :json, :accept => :json})
There is the option to turn off CSRF protection for json requests but I would rather not do that. I could go the mechanize route or something similar and then I wouldn't worry about json requests with CSRF but I just wanted to play around with doing this stuff with rest-client
I guess I'm just curious to know if there is a reason why no authenticity_token is served for json requests and I'm also wondering if there is a better way of solving the token problem than the pretty hacky approach I've taken here
Put the below code into your application controller :
def verified_request?
if request.content_type == "application/json"
true
else
super()
end
end
And call this method using before_filter .
For more details check :
http://blog.technopathllc.com/2011/09/rails-31-csrf-token-authenticity-for.html
And check this issue in rails : https://github.com/rails/rails/issues/3041
In your app/views/products/new.json.jbuilder, add this:
json.authenticity_token form_authenticity_token
This will insert a key "authenticity_token" with value being the token, so in your json_response you get the token as well. Idea from this answer.