I've been trying to authenticate the bitstamp api however, I keep on getting the following error:
"{\"error\": \"Missing key, signature and nonce parameters\"}"
The code I have written to do this is below:
let nounce = System.DateTime.Today.Ticks
let hexdigest (bytes : byte[]) =
let sb = System.Text.StringBuilder()
bytes |> Array.iter (fun b -> b.ToString("X2") |> sb.Append |> ignore)
string sb
let signature =
use hmac = new HMACSHA256(System.Text.Encoding.ASCII.GetBytes(stampsecret))
hmac.ComputeHash(mes)
|> hexdigest
I am calling the website with the following:
let ordersBTCbuy()=
Http.Request("https://www.bitstamp.net/api/buy", meth="Post", query=["key", stampkey; "signature", signature.ToLower(); "nonce", string(nounce); "amount", "1"; "price", string(convertB)])
A reference to the API can be found here: https://www.bitstamp.net/api/
Update I've changed the web address to:
let ordersBTCbuy()=
Http.Request("https://www.bitstamp.net/api/buy/", meth="Post", query=["key", stampkey; "signature", signature.ToLower(); "nonce", string(nounce); "amount", "1"; "price", string(convertB)])
My new issue is now the signature my representation is 64 characters long and upper case however I still seem to have an error.
When creating a POST request. Your key-value pairs need to go in the body.
To do that using FSharp data do the following:
let postBody = FormValues([ "key", stampkey; "signature", signature.ToLower(); "nonce", string(nounce); "amount", "1"; "price", string(convertB)])
let ordersBTCbuy()=
Http.Request("https://www.bitstamp.net/api/buy", httpMethod="Post", body=postBody)
Related
Using F# template for ASP.NET MVC. Have routes defined a la
app.UseRouting()
.UseEndpoints(fun endpoints ->
endpoints.MapGet("/", fun context ->
context.Response.WriteAsync(PageController.loadHomePage())) |> ignore
endpoints.MapGet("/contact", fun context ->
context.Response.WriteAsync(PageController.loadContactPage())) |> ignore
endpoints.MapGet("/about", fun context ->
context.Response.WriteAsync(PageController.loadAboutPage())) |> ignore
And then controller functions which all load the same page and simply sub in a title variable. The addVariable function simple replaces all instances of "[title]" with the string provided when loadTemplate is called.
module PageController
let loadHomePage() =
Theme.addVariable "title" "Home Page"
Theme.loadTemplate "index"
let loadContactPage() =
Theme.loadTemplate "index"
let loadAboutPage() =
Theme.addVariable "title" "About Us"
Theme.loadTemplate "index"
However when I navigate to /contact, which does not a have a title variable defined, it has a title of "Home Page" which means loadHomePage() is being run and setting the title variable.
Am new to ASP.NET and F# so assuming it's super simple.
Edit:
(* Add variable function adds a value to a dictionary *)
let mutable themeVars = new Dictionary<string, string>()
let addVariable name value =
themeVars.[name] <- value
(* Load template, opens a file and runs "parseVariables" on the content *)
let ParseVariables (string:string) =
Regex.Replace(string, "\[(.*?)\]",
new MatchEvaluator(
fun matchedVar ->
let varName = matchedVar.Groups.[1].ToString()
|> StringTrim
if themeVars.ContainsKey varName then
themeVars.[varName]
else
"[Undefined Variable: " + varName + "]"
))
let loadTemplate templateName =
if templateExists templateName then
templateName
|> getTemplateFilePath
|> File.ReadAllText
|> ParseVariables
else
"Missing Template: " + templateName + ""
I think the problem here is that you have a single mutable themeVars dictionary that is shared by all three pages. When your app starts, the home page is loaded, which adds a variable named "Title" to the dictionary. Then, when you visit the Contact page, that variable is still present in the dictionary, with whatever value it had last. (Could be either "Home Page" or "About Us".)
To avoid this, create a separate immutable variable lookup for each page instead. Something like this:
let loadHomePage() =
let themeVars = Map [ "Title", "Home Page" ]
Theme.loadTemplate themeVars "index"
let loadContactPage() =
let themeVars = Map.empty
Theme.loadTemplate themeVars "index"
let loadAboutPage() =
let themeVars = Map [ "Title", "About Us" ]
Theme.loadTemplate themeVars "index"
Note that I've used a Map here instead of a Dictionary, since they're easier to deal with in F#, but the idea is the same either way.
I want to send a signed POST request to Okex: Authentication Docs POST Request Docs.
I always get back an "invalid sign" error.
I successfully sent a signed GET request. For the POST you also need to add the body in the signature. If I do that, none of my signatures are valid anymore. I already verified that my signature is the same as one produced by their official Python SDK (that's why I wrote the JSON by hand. Python has spaces in the JSON). I am new to Rust so I am hoping I am missing something obvious.
OKEx client implementations in other languages: https://github.com/okcoin-okex/open-api-v3-sdk
/// [dependencies]
/// hmac="0.7.1"
/// reqwest = "0.9.18"
/// chrono = "0.4.6"
/// base64="0.10.1"
/// sha2="0.8.0"
use reqwest::header::{HeaderMap, HeaderValue, CONTENT_TYPE};
use chrono::prelude::{Utc, SecondsFormat};
use hmac::{Hmac, Mac};
use sha2::{Sha256};
static API_KEY: &'static str = "<insert your key!>";
static API_SECRET: &'static str = "<insert your secret!>";
static PASSPHRASE: &'static str = "<insert your passphrase!>";
fn main() {
let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);
let method = "POST";
let request_path = "/api/spot/v3/orders";
let body_str = "{\"type\": \"market\", \"side\": \"sell\", \"instrument_id\": \"ETH-USDT\", \"size\": \"0.001\"}";
let mut signature_content = String::new();
signature_content.push_str(×tamp);
signature_content.push_str(method);
signature_content.push_str(request_path);
signature_content.push_str(&body_str);
type HmacSha256 = Hmac<Sha256>;
let mut mac = HmacSha256::new_varkey(API_SECRET.as_bytes()).unwrap();
mac.input(signature_content.as_bytes());
let signature = mac.result().code();
let base64_signature = base64::encode(&signature);
let mut header_map = HeaderMap::new();
header_map.insert("OK-ACCESS-KEY", HeaderValue::from_str(API_KEY).unwrap());
header_map.insert("OK-ACCESS-SIGN", HeaderValue::from_str(&base64_signature).unwrap());
header_map.insert("OK-ACCESS-TIMESTAMP", HeaderValue::from_str(×tamp).unwrap());
header_map.insert("OK-ACCESS-PASSPHRASE", HeaderValue::from_str(PASSPHRASE).unwrap());
header_map.insert(CONTENT_TYPE, HeaderValue::from_static("application/json; charset=UTF-8"));
let client = reqwest::Client::new();
let mut complete_url = String::from("https://okex.com");
complete_url.push_str(request_path);
let res = client
.post(complete_url.as_str())
.headers(header_map)
.body(body_str)
.send().unwrap().text();
println!("{:#?}", res);
}
This returns an "Invalid Sign" error at the moment but should return a successful http code (if enough funds are on the account).
Solution was to use "https://www.okex.com" instead of "https://okex.com. The latter produces the "Invalid Sign" error. But just for POST requests. Issue was therefore not Rust related.
Coming from nodejs where I could chain asynchronous events using Promises and then operator I'm trying to explore how things are done in idiomatic F#.
The calls I'm trying to chain are HTTP rest calls on some entity from creation to update to uploading images to publishing.
Function composition says the output of one function should match the input of the second one to be composed and that common input and output in my case will be string, i.e. JSON serialized string as input and output of all of these functions.
I've learned that you can compose functions using >> operator. Ideally functions should not throw errors but things happen with IO, for instance in this case what if the id of the entity I'm trying to create exists etc.
The unknown and the question is what happens if an error occurs during the chained sequence, how the caller will know what went wrong along with description message? The operation could fail in the middle or towards the end or right in the beginning of the chain sequence.
What I'm expecting from these functions upon error to stop executing the chain and return the error message to the caller. Error message is also a JSON string so there's no incompatibility between inputs and outputs of a function so you know.
I looked at Choice too but not sure if that's the direction I should be going for.
The code is not necessarily complete and all I'm looking for a is a direction to research further to get answers and possibly improve this question. Here's some code to start with.
let create schema =
// POST request
"""{"id": 1, "title": "title 1"}""" // result output
let update schema =
// PUT request, update title
"""{"id": 1, "title": "title 2"}""" // output
let upload schema =
// PUT request, upload image and add thumbnail to json
"""{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}"""
let publish schema =
// PUT request, publish the entity, add url for the entity
if response.StatusCode <> HttpStatusCode.OK then
"""{"code": "100", "message": "file size above limit"}"""
else
"""{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""
let chain = create >> update >> upload >> publish
Edit - Attempt
Trying to parameterize the image thumbnail in the upload part
let create (schema: string) : Result<string,string> =
Ok """{"id": 1, "title": "title 1"}""" // result output
let update (schema: string) : Result<string,string> =
Ok """{"id": 1, "title": "title 2"}""" // output
let upload2 (img: string) (schema: string) : Result<string,string> =
printf "upload image %s\n" img
let statusCode = HttpStatusCode.OK
match statusCode with
| HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}"""
| x -> Error (sprintf "%A happened" x)
let publish (schema: string) =
let statusCode = HttpStatusCode.InternalServerError
match statusCode with
| HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""
| _ -> Error """{"code": "100", "message": "couldn't publish, file size above limit"}"""
let chain = create >> Result.bind update >> Result.bind (upload2 "image.jpg") >> Result.bind publish
A good general approach to this problem is wrapping your functions' return values in a Choice/Either-like type and using a higher-order function to bind them together such that a failure propagates/short-circuits with some meaningful data. F# has a Result type with a bind function that can be used like this:
type MyResult = Result<string,string>
let f1 x : MyResult = printfn "%s" x; Ok "yep"
let f2 x : MyResult = printfn "%s" x; Ok "yep!"
let f3 x : MyResult = printfn "%s" x; Error "nope :("
let fAll = f1 >> Result.bind f2 >> Result.bind f3
> fAll "howdy";;
howdy
yep
yep!
[<Struct>]
val it : Result<string,string> = Error "nope :("
The first two functions succeed, but the third fails and so you get an Error value back.
Also check out this article on Railway-oriented programming.
Update to be more specific to your example:
let create (schema: string) : Result<string,string> =
Ok """{"id": 1, "title": "title 1"}""" // result output
let update (schema: string) : Result<string,string> =
Ok """{"id": 1, "title": "title 2"}""" // output
let upload (schema: string) =
let statusCode = HttpStatusCode.OK
match statusCode with
| HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg"}"""
| x -> Error (sprintf "%A happened" x)
let publish (schema: string) =
let statusCode = HttpStatusCode.InternalServerError
match statusCode with
| HttpStatusCode.OK -> Ok """{"id": 1, "title": "title 2", "thumbnail": "image.jpg", "url": "http://example.com/1"}"""
| _ -> Error """{"code": "100", "message": "file size above limit"}"""
let chain =
create >> Result.bind update >> Result.bind upload >> Result.bind publish
I would like to decode an API response in which one of the fields value (category) would determine how to decode another field (configuration) using different sub-decoders.
I was able to accomplish such thing using Json.Decode.mapn functions and the andThen function, but I was wondering if there is any way to do such thing using elm-decode-pipeline as it has a nicer API and I will run out of mapn functions eventually.
A minimmum and somewhat trivial example would be like this:
type alias Machine =
{ name : String
, specs : MachineSpecs
}
type MachineSpecs
= ElectricMachine ElectricSpecs
| MechanicalMachine MechanicalSpecs
| UnknownMachine
type alias ElectricSpecs =
{ voltage : Int
}
type alias MechanicalSpecs =
{ gears : Int
}
And some valid JSON responses would have these shapes:
{
"name": "Foo electric machine",
"category": "electric",
"configuration": {
"voltage": 12
}
}
{
"name": "Bar mechanical machine",
"category": "mechanical",
"configuration": {
"gears": 5
}
}
{
"name": "Some machine of unknown category",
"category": "foo"
}
I tried a similar approach to the one I was using with the mapn functions, but it doesn't work.
decoder : Decoder Machine
decoder =
decode Machine
|> required "name" string
|> required "category" (string |> andThen catDec)
catDec : String -> Decoder MachineSpecs
catDec cat =
case cat of
"electric" ->
map ElectricMachine electricDecoder
"mechanical" ->
map MechanicalMachine mechanicalDecoder
_ ->
succeed UnknownMachine
electricDecoder : Decoder ElectricSpecs
electricDecoder =
decode ElectricSpecs
|> requiredAt [ "configuration", "voltage" ] int
mechanicalDecoder : Decoder MechanicalSpecs
mechanicalDecoder =
decode MechanicalSpecs
|> requiredAt [ "configuration", "gears" ] int
In fact, I haven't seen any example on the web or docs using both Json.Decode.Pipeline and andThen at the same time, so I'm not sure if it's even possible.
I have set up an online example of this issue showing how it fails to decode the conditional part: https://runelm.io/c/3ut
As an alternative, you could place your andThen bindings before the pipeline (ellie example):
decoder : Decoder Machine
decoder =
field "category" string
|> andThen catDec
|> andThen
(\cat ->
decode Machine
|> required "name" string
|> hardcoded cat
)
If you are running out of mapN numbers, consider switching to andMap (or the infix version |:) in the elm-community/json-extra package.
Chad Gilbert's answer just works (thanks!) and it lead me to read the Json.Decode.Pipeline source code to understand a bit more about how the piping was implemented and I've found an alternative solution that is a bit more concise, so I thought about sharing it here:
decoder : Decoder Machine
decoder =
decode Machine
|> required "name" string
|> custom (field "category" string |> andThen catDec)
Hi I am new to swift please spare me.
I need to post to particular API but the api is not a fan of key value pair the api expect raw json as post data
I use this library here to make post request.
this is my code
func postItem(itemname: String, itemnumber: Int, itemcode:String, url:String, baseURL:String, completion: (result: Dictionary<String, AnyObject>) -> ()){
var dict: Dictionary<String, AnyObject>!
var params: Dictionary<String,AnyObject> = ["parentItem": ["itemname":itemname,"itemnumber":itemnumber,"itemcode":code]]
let data = NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted, error: nil)
let string = NSString(data: data!, encoding: NSUTF8StringEncoding)
var request = HTTPTask()
request.requestSerializer = JSONRequestSerializer()
request.requestSerializer.headers[headerKey] = getToken() //example of adding a header value
request.POST(url, parameters: params, success: {(response: HTTPResponse) in
if response.responseObject != nil {
let data = response.responseObject as NSData
var error: NSError?
dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as Dictionary<String, AnyObject>;
completion(result: dict)
}
},failure: {(error: NSError, response: HTTPResponse?) in
dict = ["error" : "error" ]
completion(result: dict)
})
}
i need to pass this kind of raw json in api
eg. {"parentItem": {"itemname":"Cocoa","itemnumber":123,"itemcode":"cocoa-12-A"}}
but when I println my params because it is dictionary it generate something like
["parentItem": ["itemname"="Cocoa"; "itemnumber"=123; "itemcode"="cocoa-12-A"]]
I just couldn't convert the params to JSON because the library I'm using is expecting dictionary and I'm having a hard time creating my own class.
could anyone help me? any comments and suggestion would do. Thanks in advance.
Why don't use Alamofire framework ? It's pretty good and sends standard json