Is there any less complicated solution for the following task?
For working with API I need to calculate signature using the formula below.
Problem comes from double quotes in request body, they stored as \" not ".
Code below generate text 1570702210SoMeF#ke123456[{ "id": "123", "title": "foo", "version": "2019-10-10 10:10:10 } ]}SoMeF#ke123456 and correct hash is "b6e783309e9d6f8ee47647373a9f6086020b3af8" by http://www.sha1-online.com/
Signature formula:
hex( sha1({GMT_UNIXTIME} + {API_SECRET} + {CONTENT} + {API_SECRET}) ), where
hex() - function which convert binary data into hexadecimal format
sha1() - standard hash-function SHA-1, must return binary data
text string concatenation
{API_SECRET} - a secret key which is issued together with login {API_LOGIN}
{CONTENT} - request body
Following code gives incorrect signature "c7a7ecbb0fd2d6eebfb378bdd061ea88d9fb2f69".
library(stringr)
library(lubridate)
library(digest)
API_SECRET <- 'SoMeF#ke123456'
mstime <- ymd_hms('2019-10-10 10:10:10')
my_id <- 123
title1 <- 'foo'
request_body_json <- paste0('[{ "id": "', my_id,'", "title": "', title1, '", "version": "', mstime, ' } ]}')
rbj1 <- paste0(round(as.numeric(mstime)), API_SECRET, request_body_json, API_SECRET)
signature <- digest(rbj1, algo = "sha1")
I see a workaround with saving string to file with cat() function and calculate signature from file, that gives correct signature "b6e783309e9d6f8ee47647373a9f6086020b3af8"
cat(paste0(round(as.numeric(mstime)), API_SECRET, request_body_json, API_SECRET), file = 'rbj.txt')
signature <- digest('rbj.txt', algo = "sha1", file = TRUE)
Prevent the input being serialized:
digest(rbj1, algo = "sha1", serialize = FALSE)
[1] "b6e783309e9d6f8ee47647373a9f6086020b3af8"
Related
I have some IDs that I want to eventually loop into a larger variable:
playerId <- c(12345, 23456, 34567)
But to first do that, I need to use sprintf to create the necessary lines of code that will run correctly in an API request that looks like something like this when I'm running one at a time:
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = VanAPI),
encode = "json",
body=list(playerId = 12345)
)
When I run the above request, it works just fine. But for the purposes of a loop, I want it to look like this:
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = ApiKey),
encode = "json",
PlayerIdLines
)
So what I'm doing is creating a series of the necessary line I need for each ID:
PlayerIdLines <- cat(sprintf('body=list(playerId = %s\n)', playerId))
When I first run that line, it produces this output:
> PlayerIdLines <- cat(sprintf('body=list(playerId = %s\n)', playerId))
body=list(targetId = 12345
) body=list(targetId = 23456
) body=list(targetId = 34567
)
But then after that, whenever I try to execute variable PlayerIdLines, all it does is return null:
> PlayerIdLines
NULL
Why is that happening? Why is it being stored as NULL?
EDIT: BASED ON MR FLICK'S ANSWER
I try running the following:
get_data <- function(url) {
POST(
'https://api.secure.com/v1/Test',
accept_json(),
content_type_json(),
add_headers(Authorization = VanAPI),
encode = "json",
body=list(playerId = playerId)
)
}
map_df(playerIds, get_data, .id = 'log') -> CreateDF
But I'm met with the following error:
Error: Argument 1 must be a data frame or a named atomic vector.
I am trying to get data from Eikon Elektron cloud platform.
I ran following codes from https://github.com/Refinitiv/websocket-api/blob/master/Applications/Examples/R/market_price_authentication.R:
library(curl)
> content = paste("grant_type=", "password","&username=", user, "&password=", password, sep="")
> h <- new_handle(copypostfields = content)
> h
<curl handle> (empty)
> handle_setheaders(h,
+ "Content-Type" = "application/x-www-form-urlencoded"
+ )
> handle_setopt(h, ssl_verifypeer = FALSE, ssl_verifyhost = FALSE)
> auth_url = paste("https://", auth_hostname, sep="")# ":", auth_port, "/getToken", sep="")
> auth_url
[1] "https://api.refinitiv.com/auth/oauth2/v1/token"
> req <- curl_fetch_memory(auth_url, **handle = h**)
> req
$url
[1] "https://api.refinitiv.com/auth/oauth2/v1/token"
$status_code
[1] 400
$type
[1] "application/json"
**> h
<curl handle> (https://api.refinitiv.com/auth/oauth2/v1/token)**
> res_headers = parse_headers(req$headers)
> auth_json_string = rawToChar(req$content)
> auth_json = fromJSON(auth_json_string)
> cat(toJSON(auth_json, pretty=TRUE, auto_unbox=TRUE))
{
"error": "invalid_request"
}
As you can see, I got invalid request error. I think the problem lies in curl_fetch_memory and that the handle=h is using same input as auth_url, however it should use something similiar to the input of content. What can I change in my code to make it work?
I found solution how to access the URL. In github was wrongly written that app_id in R file should equal to the code from the App Key generator in Reuters. However, app_id and client_id are different things and you should add client_id=value from App Key generator (not app_id).+ also do not forget to include trapi and etc.. to your content.
I have no problem to query Mediawiki API of French Wikipedia for strings without accents:
string <- 'chien'
string <- stringi::stri_enc_toutf8(string, is_unknown_8bit = FALSE, validate = FALSE)
apiQuery <- paste0('https://fr.wikipedia.org/w/api.php?action=query&format=xml&titles=', string)
page <- xml2::read_xml(apiQuery)
{xml_document}
[1] \n \n \n \n \n <page _idx="2736914" pageid="2736914 ...
but I have problem for strings with accents:
string <- 'être'
string <- stringi::stri_enc_toutf8(string, is_unknown_8bit = FALSE, validate = FALSE)
apiQuery <- paste0('https://fr.wikipedia.org/w/api.php?action=query&format=xml&titles=', string)
page <- xml2::read_xml(apiQuery)
I receive the following error :
Error in open.connection(x, "rb") : HTTP error 400.
You need to encode the query in HTML escapes:
page <- xml2::read_xml(URLencode(apiQuery))
This changes the "ê" to "%C3%AA".
I have this piece of code to download the hex content of a file with import parameter file id. I want to insert a new attachment for a notification, but I don't know how to get started.
METHOD GET_SINGLE_ATTACHMENT_CONTENT.
" VARIABLES
DATA: HEXCONT TYPE TABLE OF SOLIX.
DATA: DOCDATA TYPE SOFOLENTI1.
DATA: LV_LENGTH TYPE I.
" CHECK TO CONTINUE FUNCTION MODULE
IF FILE_ID IS INITIAL. "type = SOFOLENTI1-DOC_ID.
MESSAGE 'Document ID is empty.' TYPE 'E' RAISING DOC_ID_EMPTY.
ENDIF.
" GET BINARY CONTENT OF FILE
CALL FUNCTION 'SO_DOCUMENT_READ_API1'
EXPORTING
DOCUMENT_ID = FILE_ID
IMPORTING
DOCUMENT_DATA = DOCDATA
TABLES
CONTENTS_HEX = HEXCONT.
IF SY-SUBRC <> 0.
MESSAGE 'Error downloading file.' TYPE 'E' RAISING FILE_DOWNLOAD_ERROR.
ENDIF.
" CONVERT TO XSTRING
LV_LENGTH = DOCDATA-DOC_SIZE.
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
INPUT_LENGTH = LV_LENGTH
IMPORTING
BUFFER = EV_RETURN "type XSTRING
TABLES
BINARY_TAB = HEXCONT.
IF SY-SUBRC <> 0.
MESSAGE 'Error downloading file.' TYPE 'E' RAISING FILE_DOWNLOAD_ERROR.
ENDIF.
ENDMETHOD.
I've read about function modules like 'SO_DOCUMENT_INSERT_API1' and it has the file information but not the file content (preferably hex content). Any idea on how to get started with this?
Maybe you can do something with the approach I used. Check this example below.
Start with parsing your data to hex
Insert the document with so_document_insert_api1
Link it to your notification with the fm binary_relation_create
" TYPES
TYPES: BEGIN OF TYPE_FILE,
NAME TYPE STRING,
TYPE TYPE STRING,
QMNUM TYPE QMNUM,
USER TYPE CHAR64,
HEXCONT TYPE XSTRING,
END OF TYPE_FILE.
" VARIABLES AND OBJECTS
DATA: LT_RETURN TYPE TABLE OF BAPIRET2.
DATA: LT_HEXCONT TYPE TABLE OF SOLIX.
DATA: LS_DOCDATA TYPE SODOCCHGI1.
DATA: LS_DOCINFO TYPE SOFOLENTI1.
DATA: LS_FILE TYPE TYPE_FILE.
DATA: LV_DOCTYPE TYPE SOODK-OBJTP.
DATA: LV_FOLDER_ID TYPE SOOBJINFI1-OBJECT_ID.
DATA: LV_LENGTH TYPE I.
DATA: OBJ_NOTIF TYPE BORIDENT.
DATA: OBJ_ATTACH TYPE BORIDENT.
DATA: P_QMNUM TYPE QMNUM.
LV_FOLDER_ID = 'FOL40000000000004'.
" CONVERT HEX CONTENT TO BINARY
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
BUFFER = LS_FILE-HEXCONT
IMPORTING
OUTPUT_LENGTH = LV_LENGTH
TABLES
BINARY_TAB = LT_HEXCONT.
" SET VALUES
LS_DOCDATA-OBJ_DESCR = LS_FILE-NAME.
LS_DOCDATA-OBJ_LANGU = 'E'.
LS_DOCDATA-OBJ_NAME = 'MESSAGE'.
LS_DOCDATA-DOC_SIZE = XSTRLEN( LS_FILE-HEXCONT ).
LV_DOCTYPE = LS_FILE-TYPE.
UNPACK LS_FILE-QMNUM TO P_QMNUM.
" CREATE ATTACHMENT
CALL FUNCTION 'SO_DOCUMENT_INSERT_API1'
EXPORTING
FOLDER_ID = LV_FOLDER_ID
DOCUMENT_DATA = LS_DOCDATA
DOCUMENT_TYPE = LV_DOCTYPE
IMPORTING
DOCUMENT_INFO = LS_DOCINFO
TABLES
CONTENTS_HEX = LT_HEXCONT.
" CREATE LINK TO OBJECT (Notification)
OBJ_NOTIF-OBJKEY = P_QMNUM.
OBJ_NOTIF-OBJTYPE = 'BUS2038'.
OBJ_ATTACH-OBJKEY = LS_DOCINFO-DOC_ID.
OBJ_ATTACH-OBJTYPE = 'MESSAGE'.
CALL FUNCTION 'BINARY_RELATION_CREATE'
EXPORTING
OBJ_ROLEA = OBJ_NOTIF
OBJ_ROLEB = OBJ_ATTACH
RELATIONTYPE = 'ATTA'.
" COMMIT
COMMIT WORK.
Is is necessary to open the contenct as hex?
You probably just want to read / write on a file. Try open OPEN DATASET
https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abapset_dataset.htm
I'm trying to access Bitfinex via api but struggling to properly authenticate my request. There is a Python example of what I want to do (https://gist.github.com/jordanbaucke/5812039) but I can't seem to get it to work in R.
key <- c("MY API KEY")
secret = c("MY API SECRET")
req <- GET("https://api.bitfinex.com/v1/balances",
authenticate(key, secret))
add_headers(X-BFX-APIKEY = key))
stop_for_status(req)
content(req)
Can someone tell me what I'm doing wrong?
/v1/balances is a Bitfinex authenticated endpoints, thus it requires the POST request with a proper handling of payload and headers.
Here is a working example from my own script:
library(httr)
key <- "..."
secret <- "..."
# payload JSON object, the request should refer to the URL
# nonce should always be greater than for previous calls
payload_json <- list(request = '/v1/account_infos', nonce = as.character(as.numeric(as.POSIXct(Sys.time()))))
# creating string from JSON payload
payload <- jsonlite::toJSON(payload_json, auto_unbox = TRUE)
# encoding payload string
payload_str <- base64enc::base64encode(charToRaw(as.character(payload)))
# adding three Bitfinex headers:
# X-BFX-APIKEY = key
# X-BFX-PAYLOAD = base64 encoded payload string
# X-BFX-SIGNATURE = sha384 encrypted payload string with the secret key
req <- POST("https://api.bitfinex.com/v1/account_infos",
add_headers('X-BFX-APIKEY' = key,
'X-BFX-PAYLOAD' = payload_str,
'X-BFX-SIGNATURE' = openssl::sha384(payload_str, key = secret))
)
content(req)
For creating "New Order" you only need to change the payload to something, like this:
payload_json <- list(request = '/v1/account_infos',
nonce = as.character(as.numeric(as.POSIXct(Sys.time()))),
symbol = 'BTCUSD',
amount = '0.3',
price = '1000',
exchange = 'bitfinex',
side = 'sell',
type = 'exchange market'
)
The rest of the code will work without changes.
For list of payload parameters check the Bitfinex API docs, e.g. "New Order".