Reputation: 357
I am trying to use OCaml's Url and Cohttp modules in order to access an API and retrieve JSON data. I am NOT trying to do this in an asynchronous way. I have no experience with web/network programming and all of the module documentation just gives signatures for types and methods (not much help to me since I do not know what they do). I am trying to access the bitstamp API and retrieve the bid price for a bitcoin. So far I only know how to declare a URI
let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/";;
but I do now know how to make a call to the uri in order to retrieve the json data. How can I use existing libraries to accomplish this? I already know how to parse json data into types that I need.
Upvotes: 2
Views: 3036
Reputation: 4246
Here's another example that you may find useful. I don't depend on Core or Async in this example, and you should be able to run it as a script rather than in a toplevel.
#! /usr/bin/env ocaml
#use "topfind"
#require "uri"
#require "cohttp.lwt"
let fetch uri =
let open Lwt in
Cohttp_lwt_unix.Client.get uri >>= fun (resp, body) ->
Cohttp_lwt_body.to_string body >>= fun b ->
Lwt_io.printl b
let () =
let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/" in
Lwt_main.run (fetch bitstamp_uri)
Upvotes: 1
Reputation: 3134
utop [0]: #require "async";;
utop [1]: #require "cohttp.async";;
utop [2]: open Async.Std;;
utop [3]: let get_uri uri_str = Cohttp_async.Client.get @@ Uri.of_string uri_str
>>= fun (_, body) -> Cohttp_async.Body.to_string body;;
val get_uri : string -> string Deferred.t = <fun>
utop [4]: get_uri "http://www.bitstamp.net/api/ticker/";;
- : string = "{\"high\": \"661.11\", \"last\": \"652.65\", \"timestamp\":
\"1402207587\", \"bid\": \"651.99\", \"vwap\": \"654.52\", \"volume\":
\"3022.07902416\", \"low\": \"648.87\", \"ask\": \"654.29\"}"
takes me a while to figure it out, so I just post the code here.
Upvotes: 1
Reputation: 1739
Here's an answer using Curl
, which doesn't require you to understand Async. (For the record, I think you're better off using Async and Cohttp, though!)
(* Wrapper for Curl. Used by the function below. *)
let fetch (url: string) (f: string -> int): unit =
let c = Curl.init () in
Curl.set_url c url;
Curl.set_followlocation c true;
Curl.set_writefunction c f;
Curl.perform c;
Curl.cleanup c
;;
(* [get url] fetches the document at [url] and returns its contents as a string. *)
let get (url: string): string =
let buf = Buffer.create 16 in
fetch url (fun s -> Buffer.add_string buf s; String.length s);
Buffer.contents buf
;;
Upvotes: 3
Reputation: 3030
Cohttp requires you to either use Lwt or Async, so you'll have to learn one of these libraries. Luckily, retrieving JSON text and parsing it is exactly one of the examples in the new Real World OCaml book, which you can read free online here. Chapter 18 covers Async and Cohttp and Chapter 15 covers JSON parsing.
Now, to actually answer your question:
$ utop
utop # #require "lwt.syntax";;
utop # #require "core";;
utop # open Core.Std;;
utop # #require "cohttp.lwt";;
utop # #require "uri";;
utop # let get_uri uri : string Or_error.t Lwt.t =
let open Lwt in
match_lwt Cohttp_lwt_unix.Client.get uri with
| None ->
let msg = sprintf "%s: no reply" (Uri.to_string uri) in
return (Or_error.error_string msg)
| Some (_, body) -> (
lwt body = Cohttp_lwt_body.string_of_body body in
return (Ok body)
);;
utop # let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/";;
utop # get_uri bitstamp_uri;;
- : string Or_error.t =
Core_kernel.Result.Ok
"{\"high\": \"755.00\", \"last\": \"675.20\", \"timestamp\": \"1384841189\", \"bid\": \"675.10\", \"volume\": \"72858.24608402\", \"low\": \"471.26\", \"ask\": \"675.20\"}"
I used Core and Lwt in this case. The RWO book uses Async. If you want to avoid the complexity of asynchronous programming completely, then you cannot use Cohttp.
Upvotes: 5