Following this page (https://django-oauth-toolkit.readthedocs.org/en/latest/rest-framework/getting_started.html), I was able to setup OAuth for my django project.
The following curl command gives me a token to access resource.
curl -X POST
-d "grant_type=password&username=<user_name>&password=<password>"
-u"<client_id>:<client_secret>" http://localhost:8000/o/token/
However, when I send request using Alamofire, things are a bit strange. This is my code
Alamofire.request(.POST, url, parameters: parameters, encoding: .JSON)
.authenticate(user: client_ID, password: client_Secret)
where parameter is a dictionary
[
"password": <password>,
"grant_type": password,
"username": <username>
]
Using curl command, I can see from Django that request.POST.items() returns the list of parameters. However, using Alamofire, there is nothing. The parameters appeared in request.body instead!
This problem is driving me crazy. Any help will be grateful!
Thanks in advance.
Well, your curl command is posting as Content-Type: application/x-www-form-urlencoded format, whereas you are forcing to post as json (.JSON). For this reason the request has passed as application/json to your django and you are seeing the parameter in body instead of POST.items().
So remove this from your code encoding: .JSON.
Related
I’m trying to use a cloudflare worker (Pasted below) to send an SMS message via the Twilio API. The CURL request (also pasted below) I’m basing the worker off of works.
Based on the 400 error from the worker the message body isn’t passed in correctly
{"code": 21602, "message": "Message body is required.", "more_info": "https://www.twilio.com/docs/errors/21602", "status": 400}
but the code looks fine to me. We can at least confirm the header is passed correctly because messing with the authorization value changes the error.
I also looked at the example POST request in the template gallery and can’t see a reason for the failure.
https://developers.cloudflare.com/workers/templates/pages/post_json/
What do i need to change in my worker code to make the POST request work?
Note: i recognize i shouldn’t put the Twilio Auth token in the body but I’ll rotate the key later.
async function handleRequest(request) {
const init = {
body: JSON.stringify(body),
method: 'POST',
headers: {
'content-type': 'application/json',
'Authorization': "Basic " + btoa('[account id]:[Authtoken]'),
},
}
return await fetch(url, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
const url = 'https://api.twilio.com/2010-04-01/Accounts/[Account id]/Messages.json'
const body = {
Body:"Hello World",
From:"+[some number]",
To:"+[some number]]",
}
curl 'https://api.twilio.com/2010-04-01/Accounts/[Account id]/Messages.json' -X POST \
--data-urlencode 'To=+[some number]' \
--data-urlencode 'From=+[some number]' \
--data-urlencode 'Body=Hello World' \
-u [account id]:[auth token]
because Twilio requires application/x-www-form-urlencoded.
REST API: Your Request
Creating or updating a resource involves performing an HTTP PUT or
HTTP POST to a resource URI. In the PUT or POST, you represent the
properties of the object you wish to update as form urlencoded
key/value pairs. Don't worry, this is already the way browsers encode
POSTs by default. But be sure to set the HTTP Content-Type header to
"application/x-www-form-urlencoded" for your requests if you are
writing your own client.
Both GET and POST methods supported by the endpoint. The POST method is recommended to call endpoint with a huge number of user ids to follow, because the GET method will lead to an oversized URL that the server can't handle. How the "follow" parameter can be passed in the body of the request?
UPD: here is what I've already tried using Insomnia (the URL is always 'https://stream.twitter.com/1.1/statuses/filter.json' and the method is always 'POST' and the server response is always "No filter parameters found. Expect at least one parameter: follow track locations"):
A plain text body with Content-Type: text/html
follow=2731236345
A json body with Content-Type: application/json
{
"follow": "2731236345"
}
Another json body
{
"follow": [
2731236345
]
}
However, when I use form-url-encoded with field "follow" and the value "2731236345" I receive the response "Unauthorized".
First of all, consider looking at the Twitter Developer Labs new endpoint, because this existing API will be retired, likely (but not yet confirmed) in 2020.
When you say "without any success", what libraries are you using, and at what levels of query parameters - you're not being very clear about what is not working here. 5000 user IDs is very large. Can you please be more specific about the errors you're seeing, and the code you're trying to run?
I've managed to connect using curl:
curl --request POST \
--url 'https://stream.twitter.com/1.1/statuses/filter.json' \
--header 'authorization: <censored>' \
--data 'follow=2731236345'
The same request doesn't work in Insomnia for some reason, but it doesn't matter for the goal of this post.
I am trying to get the file contents on Box through their API in Swift.
curl -L https://api.box.com/2.0/files/file_id/content -H "Authorization: Bearer access_token"
returns the right contents, but
curl https://api.box.com/2.0/files/file_id/content -H "Authorization: Bearer access_token"
does not.
So the "-L" part seems to be critical.
So far I have
let headers = [
"grant_type": "client_credentials",
"Authorization": "Bearer \(token)",
"scope": "public"
]
Alamofire.request("https://api.box.com/2.0/files/file_id/content", headers: headers).responseJSON { responseFile in
if let dataFile = responseFile.result.value {
print("JSON: \(dataFile)")
}
}
How can I add the "-L" part to this?
The overall structure should be correct since I can successfully get the metadata for the file by removing "/content" from the url.
According to curl manual -L/--location argument means
If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option will make curl redo the request on the new place.
So, I guess, you must check response statusCode and if it will be 3xx you need to handle redirects. Check Alamofire framework documentation about that.
Also good to read about fundamentals Handling Redirects and Other Request Changes
Based on a-a-m's answer, I got it working with the following code.
Note that I used responseString instead of responseJSON for the second request since the response was in a file format rather than in JSON format.
Alamofire.request("https://api.box.com/2.0/files/\(file_id)/content", headers: headers).responseJSON { responseFile in
if let newUrl = responseFile.response?.url {
print("new link: \(newUrl)")
//make another request using the redirection url
Alamofire.request(newUrl).responseString { content in
let filecontent = content.result.value
print (filecontent)
self.contentText.text = filecontent
debugPrint(contents)
}
}
}
}
I am using an API provided by my web host with whom I can register new clients and domains. Unfortunately they don't provide much documentation (basically none) and I'm not very used to cURL
They give ONE and very superficial example of how to create a new client, and it is as follows
curl -d "clienteTipo=I&clienteCPFCNPJ=00112135045&clienteEmpresa=NomeEmpresa&clienteNome=meunome&clienteEmail=email#dominio.com.br&clienteEmailCobranca=emailcobranca#dominio.com.br&clienteSenhaPainel=654321&clienteFone=555100000000&clienteFax=555100000001&clienteCEP=44587421&clienteEndereco=ruanome&clienteBairro=meubairro&clienteCidade=porto alegre&clienteEstado=rs&clienteLimiteMapeamento=1&clienteLimiteSubdominio=2&clienteLimiteMysql=3&clienteLimiteMssql=1&clienteLimitePgsql=1&clienteLimiteFirebird=1&clienteLimiteFTPADD=1&clienteUniBox=on&clienteAcessoFTP=on&clienteAcessoDownloadBackup=on" -k --digest -u usuario:senha -X POST https://api.kinghost.net/cliente
How can I transform this on a cURL request on Ruby keeping the parameters as informed above?
This must be a POST, but I wonder how I have to inform these parameters, they look like a query string. And what is this Digest thing?
Here is an (untested) example using rest-client that might get you started https://github.com/rest-client/rest-client).
According to what I was able to find online, rest-client automatically supports the digest authentication that that curl request is doing.
require 'rest-client'
response = RestClient::Request.execute(
method: :post,
url: 'https://api.kinghost.net/cliente',
verify_ssl: false,
user: "usuario",
password: "senha",
headers: {
params: {
clienteTipo: "I",
clienteCPFCNPJ: "00112135045",
clienteEmpresa: "NomeEmpresa",
clienteNome: "meunome",
clienteEmail: "email#dominio.com.br",
clienteEmailCobranca: "emailcobranca#dominio.com.br",
clienteSenhaPainel: "654321",
clienteFone: "555100000000",
clienteFax: "555100000001",
clienteCEP: "44587421",
clienteEndereco: "ruanome",
clienteBairro: "meubairro",
clienteCidade: "porto alegre",
clienteEstado: "rs",
clienteLimiteMapeamento: "1",
clienteLimiteSubdominio: "2",
clienteLimiteMysql: "3",
clienteLimiteMssql: "1",
clienteLimitePgsql: "1",
clienteLimiteFirebird: "1",
clienteLimiteFTPADD: "1",
clienteUniBox: "on",
clienteAcessoFTP: "on",
clienteAcessoDownloadBackup: "on"
}
}
)
the wonders of curl :)
-k means unsecure (i.e don't check SSL)
--digest is the authentication type
-u name:password is the actual username and password
-X POST it's a post
-d "blah blah" blah blah is the payload
now onto ruby:
I would look at https://github.com/rest-client/rest-client or at https://github.com/jnunemaker/httparty
It's just a matter of figuring out how to perform the post. The digest might be tricky but IIRC it can be some via Authorization header.
after struggling for a while and testing different libraries, I used Ruby to run a system command, since cURL is not dependant on Ruby
output = `curl -d "clienteTipo=#{client_type}&clienteCPFCNPJ=#{client_id}&clienteEmpresa=#{company_name}&clienteNome=#{client_name}&clienteEmail=#{client_email}&clienteEmailCobranca=#{client_billing_email}&clienteSenhaPainel=#{password}&clienteFone=#{client_phone}&clienteFax=#{client_fax}&clienteCEP=#{client_zip_code}&clienteEndereco=#{client_address}&clienteBairro=#{client_neighborhood}&clienteCidade=#{client_city}&clienteEstado=#{client_state}&clienteLimiteMapeamento=1&clienteLimiteSubdominio=1&clienteLimiteMysql=1&clienteLimiteMssql=1&clienteLimitePgsql=1&clienteLimiteFirebird=1&clienteLimiteFTPADD=1&clienteUniBox=on&clienteAcessoFTP=on&clienteAcessoDownloadBackup=on" -k --digest -u MY_USER:MY_PASSWORD -X POST API_URL`
p output
xml = Hash.from_xml(output) #in my case it returns a XML string
Now output contains the response
I am using Ruby on Rails 4.1 and I am trying to implement an API with a custom mime type. That is, in config/initializers/mime_types.rb I register an alias as like the following:
Mime::Type.register_alias 'application/json', :my_json
From another system I am trying to access the API with curl by running a HTTP PUT request, this way:
curl http://www.my_api.org/articles.my_json --request PUT --header "Content-Type: application/json" --data-binary '{\"key\": {\"a\": \"1\", \"b\": \"2\"}}'
However, by inspecting the ArticlesController parameters in my Rails application, I get the following output (note: article parameters are "unwanted" and those duplicate the "wanted" key parameters):
Parameters: {"key": { "a"=>"1", "b"=>"2" }, "article": { "a"=>"1", "b"=>"2" }}
What is the problem? Is it a bug? How can I solve that?
Note: I have implemented and access other similar API by executing HTTP GET requests and all works as expected. The problem seems to happens only when I execute HTTP PUT requests.
#rafaelfranca - No it is not a bug. It is how wrap_parameters works. You can disable at this file in your application config/initializers/wrap_parameters.rb.
See github.