cohttp_lwt_example

A simple example of use of the DuckDuckGo API server by cohttp.lwt.


In [1]:
#require "core" ;;
#require "cohttp.lwt" ;;
#require "cohttp.top" ;;
#require "yojson" ;;


/home/opam/.opam/4.04.1/lib/base/caml: added to search path
/home/opam/.opam/4.04.1/lib/base/caml/caml.cma: loaded
/home/opam/.opam/4.04.1/lib/base/shadow_stdlib: added to search path
/home/opam/.opam/4.04.1/lib/base/shadow_stdlib/shadow_stdlib.cma: loaded
/home/opam/.opam/4.04.1/lib/sexplib/0: added to search path
/home/opam/.opam/4.04.1/lib/sexplib/0/sexplib0.cma: loaded
/home/opam/.opam/4.04.1/lib/base: added to search path
/home/opam/.opam/4.04.1/lib/base/base.cma: loaded
/home/opam/.opam/4.04.1/lib/ocaml/unix.cma: loaded
/home/opam/.opam/4.04.1/lib/ocaml/bigarray.cma: loaded
/home/opam/.opam/4.04.1/lib/fieldslib: added to search path
/home/opam/.opam/4.04.1/lib/fieldslib/fieldslib.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_compare/runtime-lib: added to search path
/home/opam/.opam/4.04.1/lib/ppx_compare/runtime-lib/ppx_compare_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/sexplib: added to search path
/home/opam/.opam/4.04.1/lib/sexplib/sexplib.cma: loaded
/home/opam/.opam/4.04.1/lib/variantslib: added to search path
/home/opam/.opam/4.04.1/lib/variantslib/variantslib.cma: loaded
/home/opam/.opam/4.04.1/lib/bin_prot/shape: added to search path
/home/opam/.opam/4.04.1/lib/bin_prot/shape/bin_shape_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/bin_prot: added to search path
/home/opam/.opam/4.04.1/lib/bin_prot/bin_prot.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_hash/runtime-lib: added to search path
/home/opam/.opam/4.04.1/lib/ppx_hash/runtime-lib/ppx_hash_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_inline_test/config: added to search path
/home/opam/.opam/4.04.1/lib/ppx_inline_test/config/inline_test_config.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_inline_test/runtime-lib: added to search path
/home/opam/.opam/4.04.1/lib/ppx_inline_test/runtime-lib/ppx_inline_test_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/core_kernel/base_for_tests: added to search path
/home/opam/.opam/4.04.1/lib/core_kernel/base_for_tests/base_for_tests.cma: loaded
/home/opam/.opam/4.04.1/lib/jane-street-headers: added to search path
/home/opam/.opam/4.04.1/lib/jane-street-headers/jane_street_headers.cma: loaded
/home/opam/.opam/4.04.1/lib/ocaml/nums.cma: loaded
/home/opam/.opam/4.04.1/lib/num-top: added to search path
/home/opam/.opam/4.04.1/lib/num-top/num_top.cma: loaded
/home/opam/.opam/4.04.1/lib/num: added to search path
/home/opam/.opam/4.04.1/lib/ppx_assert/runtime-lib: added to search path
/home/opam/.opam/4.04.1/lib/ppx_assert/runtime-lib/ppx_assert_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_bench/runtime-lib: added to search path
/home/opam/.opam/4.04.1/lib/ppx_bench/runtime-lib/ppx_bench_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_expect/common: added to search path
/home/opam/.opam/4.04.1/lib/ppx_expect/common/expect_test_common.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_expect/config: added to search path
/home/opam/.opam/4.04.1/lib/ppx_expect/config/expect_test_config.cma: loaded
/home/opam/.opam/4.04.1/lib/ppx_expect/collector: added to search path
/home/opam/.opam/4.04.1/lib/ppx_expect/collector/expect_test_collector.cma: loaded
/home/opam/.opam/4.04.1/lib/stdio: added to search path
/home/opam/.opam/4.04.1/lib/stdio/stdio.cma: loaded
/home/opam/.opam/4.04.1/lib/typerep: added to search path
/home/opam/.opam/4.04.1/lib/typerep/typerep_lib.cma: loaded
/home/opam/.opam/4.04.1/lib/core_kernel: added to search path
/home/opam/.opam/4.04.1/lib/core_kernel/core_kernel.cma: loaded
/home/opam/.opam/4.04.1/lib/sexplib/unix: added to search path
/home/opam/.opam/4.04.1/lib/sexplib/unix/sexplib_unix.cma: loaded
/home/opam/.opam/4.04.1/lib/spawn: added to search path
/home/opam/.opam/4.04.1/lib/spawn/spawn.cma: loaded
/home/opam/.opam/4.04.1/lib/ocaml/threads: added to search path
/home/opam/.opam/4.04.1/lib/core: added to search path
/home/opam/.opam/4.04.1/lib/core/core.cma: loaded
/home/opam/.opam/4.04.1/lib/bytes: added to search path
/home/opam/.opam/4.04.1/lib/result: added to search path
/home/opam/.opam/4.04.1/lib/result/result.cma: loaded
/home/opam/.opam/4.04.1/lib/lwt: added to search path
/home/opam/.opam/4.04.1/lib/lwt/lwt.cma: loaded
/home/opam/.opam/4.04.1/lib/re: added to search path
/home/opam/.opam/4.04.1/lib/re/re.cma: loaded
/home/opam/.opam/4.04.1/lib/re/re_posix.cma: loaded
/home/opam/.opam/4.04.1/lib/stringext: added to search path
/home/opam/.opam/4.04.1/lib/stringext/stringext.cma: loaded
/home/opam/.opam/4.04.1/lib/uri: added to search path
/home/opam/.opam/4.04.1/lib/uri/uri.cma: loaded
/home/opam/.opam/4.04.1/lib/re/re_emacs.cma: loaded
/home/opam/.opam/4.04.1/lib/base64: added to search path
/home/opam/.opam/4.04.1/lib/base64/base64.cma: loaded
/home/opam/.opam/4.04.1/lib/cohttp: added to search path
/home/opam/.opam/4.04.1/lib/cohttp/cohttp.cma: loaded
/home/opam/.opam/4.04.1/lib/cohttp/cohttp_lwt.cma: loaded
/home/opam/.opam/4.04.1/lib/lwt/lwt-log.cma: loaded
/home/opam/.opam/4.04.1/lib/lwt/lwt-unix.cma: loaded
/home/opam/.opam/4.04.1/lib/ipaddr: added to search path
/home/opam/.opam/4.04.1/lib/ipaddr/ipaddr.cma: loaded
/home/opam/.opam/4.04.1/lib/logs: added to search path
/home/opam/.opam/4.04.1/lib/logs/logs.cma: loaded
/home/opam/.opam/4.04.1/lib/conduit: added to search path
/home/opam/.opam/4.04.1/lib/conduit/conduit.cma: loaded
/home/opam/.opam/4.04.1/lib/conduit/conduit-lwt.cma: loaded
/home/opam/.opam/4.04.1/lib/ipaddr/unix: added to search path
/home/opam/.opam/4.04.1/lib/ipaddr/unix/ipaddr_unix.cma: loaded
/home/opam/.opam/4.04.1/lib/ssl: added to search path
/home/opam/.opam/4.04.1/lib/ssl/ssl.cma: loaded
/home/opam/.opam/4.04.1/lib/lwt_ssl: added to search path
/home/opam/.opam/4.04.1/lib/lwt_ssl/lwt_ssl.cma: loaded
/home/opam/.opam/4.04.1/lib/uri/services: added to search path
/home/opam/.opam/4.04.1/lib/uri/services/uri_services.cma: loaded
/home/opam/.opam/4.04.1/lib/conduit/conduit-lwt-unix.cma: loaded
/home/opam/.opam/4.04.1/lib/magic-mime: added to search path
/home/opam/.opam/4.04.1/lib/magic-mime/magic_mime_library.cma: loaded
/home/opam/.opam/4.04.1/lib/uchar: added to search path
/home/opam/.opam/4.04.1/lib/fmt: added to search path
/home/opam/.opam/4.04.1/lib/fmt/fmt.cma: loaded
/home/opam/.opam/4.04.1/lib/logs/logs_fmt.cma: loaded
/home/opam/.opam/4.04.1/lib/logs/logs_lwt.cma: loaded
/home/opam/.opam/4.04.1/lib/cohttp/cohttp_lwt_unix.cma: loaded
/home/opam/.opam/4.04.1/lib/cohttp/cohttp_top.cma: loaded
/home/opam/.opam/4.04.1/lib/easy-format: added to search path
/home/opam/.opam/4.04.1/lib/easy-format/easy_format.cmo: loaded
/home/opam/.opam/4.04.1/lib/biniou: added to search path
/home/opam/.opam/4.04.1/lib/biniou/biniou.cma: loaded
/home/opam/.opam/4.04.1/lib/yojson: added to search path
/home/opam/.opam/4.04.1/lib/yojson/yojson.cmo: loaded

In [2]:
open Core ;;
open Lwt.Infix ;;
open Cohttp ;;
open Cohttp_lwt_unix ;;

The default asynchronous context implemented in cohttp.lwt cannot work on IOCaml. We define a custom context based on blocking API.


In [3]:
let ctx =
  let open Caml.Unix in
  let service name =
    let s = getservbyname name "tcp" in
    Lwt.return (Some Resolver.({ name; port = s.s_port; tls = (name = "https" || name = "imaps"); })) in
  let resolver service uri =
    let host = match Uri.host uri with Some h -> h | None -> "localhost" in
    let port = match Uri.port uri with Some p -> p | None -> service.Resolver.port in
    match getaddrinfo host (string_of_int port) [AI_SOCKTYPE SOCK_STREAM] with
    | [] -> Lwt.return (`Unknown ("name resolution failed"))
    | {ai_addr=ADDR_INET (addr,port);_}::_ -> Lwt.return (`TCP (Ipaddr_unix.of_inet_addr addr, port))
    | {ai_addr=ADDR_UNIX file;_}::_ -> Lwt.return (`Unix_domain_socket file) in
  let resolver = Resolver_lwt.init ~service ~rewrites:["", resolver] () in
  Cohttp_lwt_unix_net.({ default_ctx with resolver })


Out[3]:
val ctx : Cohttp_lwt_unix_net.ctx =
  {Cohttp_lwt_unix_net.ctx = <abstr>; resolver = <abstr>}

We obtain the meaning of a given query from the DuckDuckGo API server.

Yojson is a JSON serialization/deserialization library written in OCaml, and Yojson.Basic.Util contains utilities for parsing a JSON.


In [4]:
let search_query query =
  let base_uri = Uri.of_string "http://api.duckduckgo.com/?format=json" in
  let uri = Uri.add_query_param base_uri ("q", [query]) in
  Client.get ~ctx uri >>= fun (resp, body) -> (* GET contents from a given uri *)
  assert (Response.status resp = `OK) ; (* Check HTTP response code *)
  Cohttp_lwt_body.to_string body >|= fun body -> (* Receive contents *)
  let json = Yojson.Basic.from_string body in (* Parse a JSON *)
  (* Find field "Definition" or "Abstract" in a JSON *)
  let def = Yojson.Basic.Util.(json |> member "Definition" |> to_string_option) in
  let abs = Yojson.Basic.Util.(json |> member "Abstract" |> to_string_option) in
  match def with
  | None | Some "" -> abs
  | _ -> def


Out[4]:
val search_query : string -> string option Lwt.t = <fun>

In [5]:
Lwt_main.run (search_query "ocaml")


Out[5]:
- : string option =
Some
 "OCaml, originally named Objective Caml, is the main implementation of the programming language Caml, created by Xavier Leroy, J\195\169r\195\180me Vouillon, Damien Doligez, Didier R\195\169my, Asc\195\161nder Su\195\161rez and others in 1996. A member of the ML language family, OCaml extends the core Caml language with object-oriented programming constructs."

In [ ]: