Connect R to an API, pass it username and password - python

I have been trying to retrieve data from an API using R, but haven't succeeded yet. I tried doing it in R using the httr package and the GET function, but I get the following error when I enter the URL:
Error: 'new_handle' is not an exported object from 'namespace:curl'
What it comes down to is that I want to connect to data and that I have to pass some arguments like password and username.
I do have some Python code from a colleague that works (I have anonymized the URLs that are specific to our company), what I want is to connect to the data in a similar way in R:
------------- Equivalent Python code: --------------
import urllib
import datetime as dt
import dateutil
import json
headers = {u'content-type': u'application/x-www-form-urlencoded; charset=UTF-8'}
values = {"grant_type": "password",
"username": "XXXXXXXXX",
"password": "XXXXXXXXX",
"client_id": "PS"}
ko = urllib.request.Request("XXXXXX",
urllib.parse.urlencode(values).encode("utf-8"),
headers)
token = urllib.request.urlopen(ko).read()
epic = token.decode()
token_key = epic.split(",")[0].split(":")[1].replace('"', "")
lines_to_write = list()
lines_to_write.append("Identifier;Year;Period;Park Energy Availability [%]")
start_day = dt.datetime(2015, 1, 1)
data_day = start_day
headers = {u'content-type': u'application/json', u'Authorization': 'Bearer ' + token_key}
values = {'scope': {}, 'period': {'Begin': str(data_day).replace(" ", "T"), 'End': str(data_day + dateutil.relativedelta.relativedelta(months=1)).replace(" ", "T")}}
hest = urllib.request.Request("XXXXXXXXX", json.dumps(values).encode(), headers)
data = urllib.request.urlopen(hest)
vild_hest = data.read()
Any help would be greatly appreciated,
Best regards,
Tristan

The R code for API you presented will not work since it is just simply fractions of what is needed. Below you find the structure that R needs for working towards a REST API. The username and password will be passed to API server through the body of the POST (either as stated below or it could also be added as a list in the body).
You will also have to provide a key (in below case "API-KEY"). Note that you are sending a POST to initiate the authentication with the API server. Most API server will send you back 1 or 2 keys that you will use in later communication with the API server.
It is correct that all http interaction will take help of the package httr.
GET will be used in later stage in the communication between your API client and API server but not during the first authentication phase.
POST (
url = "xxx",
add_headers(
"API-KEY" = "xxx",
"VERSION" = "2",
"Content-Type" = "application/json; charset=UTF-8",
"Accept" = "application/json; charset=UTF-8"),
body = "{identifier: xxx, password: xxx}"
)

Related

How can I solve ID error when sending request to Epic Fhir Sandbox

I'm trying to use the sandbox from https://fhir.epic.com/ for Backend Services.
I am following this tutorial : https://fhir.epic.com/Documentation?docId=oauth2&section=BackendOAuth2Guide :
I already register a new app, created a JWT (using SSL keys) tested the JWT on https://jwt.io/ : works fine! When I POST the JWT to the endpoint (https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token) I get an access token.
Using this access token, I can access a single patient Appointment ressource but that's it. I don't understand how to access other Resources like DiagnosticReport, Observations, etc. I added them in the scope of my App of course but still doesn't seems to work.
What am I missing here ?
This is my code where I can access the Appointment resource:
import json
from datetime import datetime, timedelta, timezone
import requests
from requests.structures import CaseInsensitiveDict
from jwt import (
JWT,
jwk_from_dict,
jwk_from_pem,
)
from jwt.utils import get_int_from_datetime
import random
import xmltodict
def main():
instance = JWT()
message = {
# Client ID for non-production
'iss': 'my_iss_here',
'sub': 'my_sub_here',
'aud': 'https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token',
'jti': f'7777-7777-7777-7777-7777{random.randint(100,1000)}',
'iat': get_int_from_datetime(datetime.now(timezone.utc)),
'exp': get_int_from_datetime(datetime.now(timezone.utc) + timedelta(minutes=2)),
}
# Load a RSA key from a PEM file.
with open('./privatekey.pem', 'rb') as fh:
signing_key = jwk_from_pem(fh.read())
compact_jws = instance.encode(message, signing_key, alg='RS384')
headers = {}
headers['Content-Type'] = 'application/x-www-form-urlencoded'
data = {
'grant_type': 'client_credentials',
'client_assertion_type': 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion': compact_jws
}
x = requests.post('https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token', headers=headers, data=data)
access_token = x.json()['access_token']
headers = {}
headers['Authorization'] = f'Bearer {access_token}'
x = requests.get('https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/STU3/Appointment/eWLhfjXHp4RUczv2om.1Ii2uiHcDc6rMEjO0xHBA3', headers=headers)
print(x.content)
When I change the request for one of these two (of the online tutorial), it doesn't work:
x = requests.get('https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/Observation/erXuFYUfucBZaryVksYEcMg3', headers=headers)
I'm using the FHIR ID of Camilia Lopez (test patient). She supposed to have a Observation Ressource but I get an error :
<OperationOutcome xmlns="http://hl7.org/fhir"><issue><severity value="fatal" /><code value="not-found" /><details><coding><system value="urn:oid:1.2.840.114350.1.13.0.1.7.2.657369" /><code value="59008" /><display value="The FHIR ID provided was not found." /></coding><text value="The FHIR ID provided was not found." /></details><diagnostics value="Invalid FHIR ID provided" /><location value="/f:id" /><expression value="id" /></issue></OperationOutcome>
Neither of those appear to be valid FHIR IDs for the resources requested in the Epic on FHIR sandbox. The IDs in the tutorial are just examples. You should use the test data reference here for identifying Patient and other resources that are available to test with. You should also ensure you are including all the necessary headers in your calls.

How to get temporary AWS credentials via Cognito Identity Pool

I am looking to get temporary AWS credentials through a Cognito Identity Pool to send data to a Kinesis stream through API Gateway. One thing to note is that I am trying to do this without an AWS SDK because the language it will be written in eventually does not have a compatible SDK. I am testing the solution in Python and seem to be missing something as I keep getting a 400 error. Any ideas of what I am doing wrong here?
import requests
url = 'https://cognito-identity.us-east-1.amazonaws.com' #cognito regional endpoint
headers = {
'X-AMZ-TARGET': 'com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetCredentialsForIdentity',
'X-AMZ-DATE': '20151020T232759Z'
}
body = {
'IdentityId': 'us-east-1:123456789' #identity id
}
response = requests.post(url = url, data = body, headers = headers)
print(response)
I was able to resolve the issue by adding a content type header, converting the single quotes in the body to double quotes, and wrapping the body dictionary in quotes as well.
import requests
url = 'https://cognito-identity.us-east-1.amazonaws.com' #cognito regional endpoint
headers = {
"CONTENT-TYPE": "application/x-amz-json-1.1",
"X-AMZ-TARGET": "com.amazonaws.cognito.identity.model.AWSCognitoIdentityService.GetCredentialsForIdentity",
"X-AMZ-DATE": "20151020T232759Z"
}
body = '''{
"IdentityId": "123456789"
}'''
response = requests.post(url = url, data = body, headers = headers)
print(response.text)

Consuming API with graphql queries throwing 401 error on R but working fine on Python

I have a requirement to access some information through an API. I need to do this on R. I tried doing on Python and it worked just fine but facing 401 error while doing the same operation on R.
I have the API key and also know the query to be performed. I have attached both Python and R code below.
Python:
import requests
headers = {
'Content-Type': 'application/json',
'Authorization': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX',
}
query = """
{
boards (ids: 157244624) {
permissions
}
}
"""
response = requests.get('https://XYZwebsite.com/', headers=headers, json={'query': query})
R:
require(httr)
headers = c(
`Content-Type` = 'application/json',
`Authorization` = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
)
data = '{
boards (ids: 157244624) {
permissions
}
}'
res <- GET(url = 'https://XYZwebsite.com/', add_headers(.headers=headers), body = data)
Am i missing out something in the R code? It looks pretty much the same but i am getting a 401 error on R for some weird reason.
In my case api key was expired... really long journey let me to:
amplify update api
walk through all
choose api key
enter new api key name
enter 365 days no further changes
amplify push will not detect changes, so use amplify push --force
maybe it helps
Perhaps try:
r <- GET("https://XYZwebsite.com/",
add_headers(`Content-Type` = "application/json",
`Authorization` = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"),
body = data)
Edit:
With the gist you are working off of:
Authenticate first:
token <- GQL(auth_query)$authenticate$jwtToken
Then you can run your queries by passing the token you get in the response:
GQL(current_person_query, .token = token)
Seems like you are trying to do two things at once.
If you already have the token then it looks like you are passing it incorrectly:
auth_header <- paste("bearer", .token)
res <- POST(.url, body = pbody, encode="json", add_headers(Authorization=auth_header), ...)
As it should be passed as "bearer XXXXXXXXXXXXXXXXX".

Allcoin signed POST request fails

The API i am using requires an MD5 encryption to work on POST requests. I am trying the make an 'userBalance' request to the API using the documentation https://www.allcoin.ca/api_market/market But every time it gives me back {'code': 1, 'msg': '签名校验失败'} (which means signature check failed). The API only asks for 2 parameteres, the api_key and sign. I carefully follow the guidance of the documentation, but the API still rejects the POST. Any suggestions why it fails the signature check? Am i missing something?
import hashlib
import keys
import requests
KEY = keys.allcoin["key"]
API_SECRET = keys.allcoin["secret"]
msg = "api_key='{}&secret_key={}".format(KEY, API_SECRET)
signature = hashlib.md5(msg.encode("utf-8")).hexdigest()
parameters = {
"api_key": KEY,
"sign": signature.upper(),
}
params = "&".join("{}={}".format(a, b) for a, b in parameters.items())
url = "http://www.allcoin.ca/Api_User/userBalance"
r = requests.post(
headers={
"Content-Type": "application/x-www-form-urlencoded",
'user-agent': 'my-app/0.0.1'
},
url=url,
params=parameters
)
print(r.json())
I think you want to change params=parameters to params=params in your requests.post().

Trying to interact with an API

I'm in the process of moving learning how to interact with APIs in my programming training. The following script is used on the sandbox environment for a software I'm trying to interact with.
For some reason, I cannot login to the API to run the second function. Does anyone see the issue?
# import requests library
import requests
#import json library
import json
controller='apicontroller#test.com'
def getToken():
# put the ip address or dns of your apic-em controller in this url
url = "https://" + controller + "/api/aaaLogin.json"
json_object = {
"aaaUser" : {
"attributes" : {
"name" : "******",
"pwd" : "*******"
}
}
}
#Content type must be included in the header
header = {"content-type": "application/json"}
#Performs a POST on the specified url to get the service ticket
response= requests.post(url,data=json.dumps(json_object), headers=header, verify=False)
#convert response to json format
r_json=response.json()
#parse the json to get the service ticket
token = r_json["response"]["token"]
return token
def pushtenant():
# URL for network device REST API call to get list of existing devices on the network.
url = "https://" + controller + "/api/api/mo/uni"
#Content type must be included in the header as well as the ticket
headers = {"content-type": "application/json", "X-Auth-Token":Token}
json_tenant = [{
"fvTenant" : {
"attributes" : {
"name" : "ExampleCorp"
}
}
}]
# this statement performs a GET on the specified network-device url
response = requests.post(url, json.dumps(json_tenant), headers=headers,verify=False)
# json.dumps serializes the json into a string and allows us to
# print the response in a 'pretty' format with indentation etc.
print ("Response = ")
print (json.dumps(response.json(), indent=4, separators=(',', ': ')))
enter code here
#convert data to json format.
r_json=response.json()
theToken=getToken()
pushtenant(theToken)

Categories

Resources