├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE-APACHE ├── README.md ├── info.rkt ├── main.rkt ├── private ├── core.rkt ├── params.rkt └── utils.rkt └── scribblings └── http-client.scrbl /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: main 2 | on: 3 | push: 4 | branches: 5 | - "master" 6 | jobs: 7 | main: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | racket-version: ["stable"] 12 | racket-variant: ["CS"] 13 | name: main 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: Bogdanp/setup-racket@v0.12 17 | with: 18 | architecture: x64 19 | distribution: full 20 | variant: ${{ matrix.racket-variant }} 21 | version: ${{ matrix.racket-version }} 22 | - name: Installing pkgs 23 | run: raco pkg install --no-docs --auto --name http-client 24 | - name: Compiling and building its docs 25 | run: raco setup --check-pkg-deps --unused-pkg-deps http-client 26 | 27 | - name: build docs 28 | run: | 29 | raco scribble \ 30 | --dest docs \ 31 | --dest-name index \ 32 | ++main-xref-in \ 33 | --redirect-main https://docs.racket-lang.org/ \ 34 | --redirect https://docs.racket-lang.org/local-redirect/index.html \ 35 | scribblings/http-client.scrbl 36 | - name: Deploy to GitHub Pages 37 | if: success() 38 | uses: crazy-max/ghaction-github-pages@v1.2.5 39 | with: 40 | target_branch: gh-pages 41 | build_dir: docs 42 | env: 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rkt~ 2 | *.rkt#* 3 | .#*.rkt 4 | 5 | compiled/ 6 | doc/ 7 | docs/ 8 | scribblings/compiled/ 9 | 10 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Yanying Wang 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | http-client 2 | =========== 3 | 4 | ~~~racket 5 | (require http-client) 6 | 7 | (http-get "https://httpbin.org" 8 | #:path "anything/fruits" 9 | #:data (hasheq 'color "red" 'made-in "China" 'price 10) 10 | #:headers (hasheq 'Accept "application/json" 'Token "temp-token-abcef")) 11 | ~~~ 12 | 13 | check more doc at: https://yanying.wang/http-client/ 14 | 15 | https://developer.mozilla.org/en-US/docs/Web/HTTP 16 | -------------------------------------------------------------------------------- /info.rkt: -------------------------------------------------------------------------------- 1 | #lang info 2 | (define collection "http-client") 3 | (define deps '("base" "html-parsing" "at-exp-lib" "gregor")) 4 | (define build-deps '("scribble-lib" "racket-doc" "rackunit-lib" "scribble-rainbow-delimiters")) 5 | (define scribblings '(("scribblings/http-client.scrbl" ()))) 6 | (define pkg-desc "A practical http client library for sending data to http servers.") 7 | (define version "0.2") 8 | (define pkg-authors '("Yanying Wang")) 9 | -------------------------------------------------------------------------------- /main.rkt: -------------------------------------------------------------------------------- 1 | #lang at-exp racket/base 2 | 3 | (require (for-syntax racket/base racket/syntax) 4 | (file "./private/params.rkt") 5 | (file "./private/core.rkt")) 6 | (provide (except-out (all-defined-out) define-http-methods) ;; TODO: add contracts to http-get/post... 7 | (all-from-out (file "./private/params.rkt")) 8 | (all-from-out (file "./private/core.rkt"))) 9 | 10 | (define-syntax (define-http-methods stx) 11 | (define (define-fun name) 12 | (with-syntax ([n name]) 13 | #`(define (#,(format-id #'n "http-~a" (syntax-e #'n)) url 14 | #:data [data (hasheq)] 15 | #:path [path ""] 16 | #:headers [headers (hasheq)]) 17 | (define conn 18 | (if (string? url) 19 | (http-connection url (hasheq) (hasheq)) 20 | url)) 21 | (http-do 'n conn #:data data #:path path #:headers headers)))) 22 | (syntax-case stx () 23 | [(_ names ...) 24 | (with-syntax 25 | ([(define-funs ...) 26 | (map define-fun 27 | (syntax->list #'(names ...)))]) 28 | #'(begin 29 | define-funs ...))])) 30 | (define-http-methods get head post put delete options patch) 31 | 32 | 33 | ;;;; =========> test ::: 34 | (module+ test 35 | (require rackunit) 36 | 37 | (define conn 38 | (http-connection "https://httpbin.org" (hasheq) (hasheq))) 39 | (define conn1 40 | (http-connection "https://httpbin.org/anything" (hasheq 'Content-Type "application/json" 'Accept "application/json") (hasheq 'made-in "China" 'price 10))) 41 | 42 | 43 | (check-true (current-http-client/response-auto)) 44 | 45 | (let* ([res (http-get conn)] 46 | [res-headers (http-response-headers res)] 47 | [res-body (http-response-body res)]) 48 | (check-equal? (http-response-code res) 200) 49 | (check-equal? (hash-ref res-headers 'Content-Type) 50 | "text/html; charset=utf-8") 51 | (check-true (list? (http-response-body res)))) 52 | 53 | (parameterize ([current-http-client/response-auto #f]) 54 | (check-false (current-http-client/response-auto)) 55 | (define res (http-get conn)) 56 | (define res-headers (http-response-headers res)) 57 | (define res-body (http-response-body res)) 58 | (check-true (string? (http-response-body res)))) 59 | 60 | (let* ([res (http-get conn #:path "/status/309")] 61 | [req (http-response-request res)]) 62 | (check-equal? (http-request-url req) "https://httpbin.org/status/309") 63 | (check-equal? (http-request-method req) 'get) 64 | (check-equal? (http-response-code res) 309)) 65 | 66 | 67 | (let* ([res (http-post conn1 68 | #:path "/fruits" 69 | #:data (hasheq 'color "red") 70 | #:headers (hasheq 'Token "temp-token-abcef"))] 71 | [req (http-response-request res)] 72 | [res-code (http-response-code res)] 73 | [res-headers (http-response-headers res)] 74 | [res-body (http-response-body res)]) 75 | 76 | (check-equal? (http-request-url req) 77 | "https://httpbin.org/anything/fruits") 78 | (check-equal? (http-request-method req) 'post) 79 | (check-match (http-request-headers req) 80 | (hash-table ('Accept "application/json") ('Token "temp-token-abcef"))) 81 | (check-equal? (http-request-data req) 82 | (hasheq 'color "red" 'made-in "China" 'price 10)) 83 | 84 | (check-equal? res-code 200) 85 | (check-match res-headers 86 | (hash-table ('Content-Type "application/json"))) 87 | (check-pred hash? res-body) 88 | 89 | ;; check client's request headers and data, which was responsed by the httpbin.org in the response body. 90 | (check-equal? (hash-ref res-body 'url) 91 | "https://httpbin.org/anything/fruits") 92 | (check-match (hash-ref res-body 'headers) 93 | (hash-table ('Accept "application/json") 94 | ('Token "temp-token-abcef"))) 95 | (check-equal? (hash-ref res-body 'data) 96 | "{\"price\":10,\"color\":\"red\",\"made-in\":\"China\"}")) 97 | 98 | (let* ([res (http-get conn1 99 | #:headers (hasheq 'Accept "application/x-www-form-urlencoded"))] 100 | [req (http-response-request res)] 101 | [res-code (http-response-code res)] 102 | [res-body (http-response-body res)]) 103 | (check-equal? res-code 200) 104 | (check-equal? (hash-ref res-body 'data) 105 | "price=10&made-in=China")) 106 | 107 | (let* ([res (http-get (http-connection "https://httpbin.org/anything?fruit=apple" (hasheq) (hasheq)))] 108 | [req (http-response-request res)] 109 | [res-code (http-response-code res)] 110 | [res-body (http-response-body res)]) 111 | (check-equal? res-code 200) 112 | (check-equal? (hash-ref res-body 'data) 113 | "fruit=apple")) 114 | 115 | (let* ([res (conn 'get #:path "/anything" #:data (hasheq 'fruit "apple"))] 116 | [req (http-response-request res)] 117 | [res-code (http-response-code res)] 118 | [res-body (http-response-body res)]) 119 | (check-equal? res-code 200) 120 | (check-equal? (hash-ref res-body 'data) 121 | "fruit=apple")) 122 | 123 | ;; TODO: test body of the chinese web page like www.qq.com gb2312 124 | ) 125 | -------------------------------------------------------------------------------- /private/core.rkt: -------------------------------------------------------------------------------- 1 | #lang at-exp racket/base 2 | 3 | (require racket/string racket/list racket/hash racket/port 4 | racket/match racket/format 5 | net/http-client net/uri-codec net/url-string 6 | json xml html-parsing gregor 7 | (file "./params.rkt") (file "./utils.rkt")) 8 | (provide (all-defined-out)) 9 | 10 | 11 | (struct http-connection (url headers data) 12 | #:property prop:procedure 13 | (lambda (self method 14 | #:path [path ""] 15 | #:data [data (hasheq)] 16 | #:headers [headers (hasheq)]) 17 | (http-do method self #:data data #:path path #:headers headers)) 18 | #:methods gen:custom-write 19 | [(define (write-proc self port mode) 20 | (display @~a{#} port))]) 21 | 22 | ;; TODO: http-request should be derived from http-connection 23 | (struct http-request (url method headers data) 24 | #:methods gen:custom-write 25 | [(define (write-proc rqt port mode) 26 | (display @~a{#} port) 27 | )]) 28 | 29 | (struct http-response (request code headers body) 30 | #:methods gen:custom-write 31 | [(define (write-proc self port mode) 32 | (define rqt (http-response-request self)) 33 | (define rqt-txt @~a{@(string-upcase (~a (http-request-method rqt))) @(~v (http-request-url rqt))}) 34 | (display @~a{# @(http-client-pp-kv "code" @(http-response-code self)) @(http-client-pp-kv "headers" @(http-response-headers self)) @(http-client-pp-kv "body" @(http-response-body self))>} port))]) 35 | 36 | 37 | (define (http-do method conn 38 | #:data [data1 (hasheq)] 39 | #:path [path ""] 40 | #:headers [headers1 (hasheq)]) 41 | (define hcrid (random 999999999)) 42 | (define url (string->url (http-connection-url conn))) 43 | (define data2 (http-connection-data conn)) 44 | (define data3 (make-hasheq (url-query url))) 45 | (define headers2 (http-connection-headers conn)) 46 | (define req-path1 47 | (filter non-empty-string? (map path/param-path (url-path url)))) 48 | (define req-path2 49 | (string-split path "/")) 50 | (define req-path1&2 (append req-path1 req-path2)) 51 | (define req-path1&2/encode (map uri-encode req-path1&2)) 52 | (define req-host (url-host url)) 53 | (define req-path (string-join (map (lambda (e) (string-append "/" e)) req-path1&2/encode) "")) 54 | (define req-headers (hash-union headers1 headers2 (hasheq 'User-Agent (current-http-client/user-agent)) 55 | #:combine/key (lambda (k v1 v2) v1))) 56 | (define req-data (hash-union data1 data2 data3 57 | #:combine/key (lambda (k v1 v2) v1))) 58 | (define req-headers-raw 59 | (hash-map req-headers 60 | (lambda (k v) (~a k ": " v)))) 61 | (define req-data-raw 62 | (match req-headers 63 | ;; [(? hash-empty?) ""] 64 | [(hash-table ('Content-Type "application/json")) (jsexpr->string req-data)] 65 | ;; [(hash-table ('Accept "application/x-www-form-urlencoded")) (alist->form-urlencoded (hash->list req-data))] 66 | [_ (alist->form-urlencoded (hash-map req-data 67 | (lambda (k v) 68 | (cons k (if (number? v) 69 | (number->string v) 70 | v)))))])) 71 | (when (and (eq? method 'get) (non-empty-string? req-data-raw)) 72 | (set! req-path (string-append req-path "?" req-data-raw)) 73 | (set! req-data-raw "")) 74 | (define req 75 | (http-request (string-append (url-scheme url) 76 | "://" 77 | req-host 78 | (if (url-port url) (number->string (url-port url)) "") 79 | req-path) 80 | method req-headers req-data)) 81 | 82 | (when (current-http-client/debug) 83 | (define (fmt h) 84 | (string-join (map (lambda (e) (~a " " (car e) ": " (cdr e))) (hash->list h)) "\n")) 85 | (displayln (~a "CLIENT-REQ-ID: " hcrid ", " (datetime->iso8601 (now)) "\n" 86 | (string-upcase (symbol->string (http-request-method req))) " " (http-request-url req) "\n" 87 | "HEADERS: \n" (fmt (http-request-headers req)) "\n" 88 | "DATA: \n" (fmt (http-request-data req)) "\n"))) 89 | 90 | (define-values (res-status-raw res-headers-raw res-in) 91 | (http-sendrecv req-host req-path 92 | #:ssl? (match (url-scheme url) ["https" #t] [_ #f]) 93 | #:method (string-upcase (symbol->string method)) 94 | #:port (match (url-port url) 95 | [(? integer? n) n] 96 | [#f #:when (string=? (url-scheme url) "https") 97 | 443] 98 | [_ 80]) 99 | #:headers req-headers-raw 100 | #:data req-data-raw)) 101 | (define res-body-raw (port->string res-in)) 102 | (define res-code 103 | (string->number (second (string-split (bytes->string/utf-8 res-status-raw))))) 104 | (define res-headers 105 | (for/hasheq ([e res-headers-raw]) 106 | (match (string-split (bytes->string/utf-8 e) ":") 107 | [(list-rest a b) 108 | (define k (string->symbol a)) 109 | (define v (string-trim (string-join b))) 110 | (values k v)]))) 111 | (define res-body 112 | (match res-headers 113 | [_ #:when (not (current-http-client/response-auto)) 114 | res-body-raw] 115 | [(hash-table ('Content-Type (regexp #rx"^application/json.*"))) 116 | (string->jsexpr res-body-raw)] 117 | [(hash-table ('Content-Type (regexp #rx"^text/html.*"))) 118 | (html->xexp res-body-raw)] 119 | [(hash-table ('Content-Type (regexp #rx"^(application/xml|text/xml|application/xhtml+xml).*"))) 120 | (string->xexpr res-body-raw)] 121 | [_ res-body-raw])) 122 | 123 | (when (current-http-client/debug) 124 | (define (fmt h) 125 | (string-join (map (lambda (e) (~a " " (car e) ": " (cdr e))) (hash->list h)) "\n")) 126 | (displayln (~a 127 | "CLIENT-REQ-ID: " hcrid ", " (datetime->iso8601 (now)) "\n" 128 | "RESPONSE CODE: " res-code "\n" 129 | "RESPONSE HEADERS:\n" (fmt res-headers) "\n" 130 | "RESPNOSE BODY: " res-body-raw "\n\n"))) 131 | (http-response req res-code res-headers res-body)) -------------------------------------------------------------------------------- /private/params.rkt: -------------------------------------------------------------------------------- 1 | #lang at-exp racket/base 2 | 3 | 4 | (require racket/format) 5 | (provide (all-defined-out)) 6 | 7 | 8 | (define current-http-client/pretty-print-depth 9 | (make-parameter 1)) 10 | 11 | (define current-http-client/response-auto 12 | (make-parameter #t)) 13 | 14 | (define current-http-client/user-agent 15 | (make-parameter @~a{http-client[@(system-type)/@(system-type 'vm)/@(version)]})) 16 | 17 | (define current-http-client/debug 18 | (make-parameter #f)) 19 | -------------------------------------------------------------------------------- /private/utils.rkt: -------------------------------------------------------------------------------- 1 | #lang at-exp racket/base 2 | 3 | (require racket/pretty 4 | racket/format 5 | (file "./params.rkt")) 6 | (provide (all-defined-out)) 7 | 8 | (define (http-client-pp-kv k v) 9 | (parameterize ([pretty-print-depth (current-http-client/pretty-print-depth)]) 10 | @~a{@|k|: @(pretty-format v)})) 11 | 12 | 13 | ;; (define (http-client-display data port) 14 | ;; (parameterize ([pretty-print-depth (current-http-client/pretty-print-depth)]) 15 | ;; (pretty-display data port))) 16 | 17 | 18 | ;; (pretty-print-size-hook (lambda (a b c) 1)) 19 | 20 | ;; (define (format-kv k v) 21 | ;; (define length (string-length (~a v))) 22 | ;; (define marker @~a{......[@length]}) 23 | ;; @~a{@|k|: @(~v @v #:max-width 128 #:limit-marker @marker)}) 24 | -------------------------------------------------------------------------------- /scribblings/http-client.scrbl: -------------------------------------------------------------------------------- 1 | #lang scribble/manual 2 | @(require (for-label http-client 3 | racket/base) 4 | scribble/eval 5 | scribble-rainbow-delimiters) 6 | 7 | @(define the-eval 8 | (make-eval-factory '(http-client))) 9 | 10 | @script/rainbow-delimiters* 11 | 12 | @title{HTTP Client} 13 | @author[(author+email "Yanying Wang" "yanyingwang1@gmail.com")] 14 | 15 | 16 | @defmodule[http-client] 17 | A practical Racket HTTP client for interacting data with HTTP servers. 18 | @itemlist[ 19 | @item{ 20 | In case of backwards incompatible updating, you can do the installation with: 21 | 22 | @itemlist[ 23 | @item{consulting the git commit references as @secref["concept:source" #:doc '(lib "pkg/scribblings/pkg.scrbl")]: 24 | @commandline{raco pkg install "https://github.com/yanyingwang/http-client.git#f1b55669b23c35447c0688ef0495a6abfb7c9fdd"}} 25 | 26 | @item{using git tags: 27 | @commandline{raco pkg install "https://github.com/yanyingwang/http-client.git#v0.0.1"}} 28 | ]} 29 | 30 | @item{Releases: @url{https://github.com/yanyingwang/http-client/releases}} 31 | ] 32 | 33 | @section[#:tag "common-usage-example"]{Common Usage Example} 34 | @subsection{Explicitly request URLs} 35 | Request @litchar{https://httpbin.org/anything/fruits?color=red&made-in=China&price=10} with setting request headers @litchar{Token: your-token} would be like below: 36 | @racketinput[ 37 | (http-get "https://httpbin.org" 38 | #:path "anything/fruits" 39 | #:data (hasheq 'color "red" 'made-in "China" 'price 10) 40 | #:headers (hasheq 'Token "your-token")) 41 | ] 42 | 43 | @subsection[#:tag "request-nuance-urls"]{Request nuance URLs} 44 | You can define a @racket[http-connection], and use it to do requests with modifying some details of it. 45 | 46 | @subsubsection{Define connections} 47 | Predefine a @racket[http-connection] with presetting url/path/headers/data: 48 | @racketinput[ 49 | (define httpbin-org/anthing 50 | (http-connection "https://httpbin.org/anything" 51 | (hasheq 'Content-Type "application/json") 52 | (hasheq 'made-in "China" 'price 10))) 53 | ] 54 | 55 | @subsubsection{Do the requests} 56 | Do a GET request with adding path/data/headers to the predefined @racket[http-connection]: 57 | 58 | @itemlist[ 59 | @item{Get @litchar{https://httpbin.org/anything/fruits?made-in=China&price=10&color=red} 60 | with setting request headers to @litchar{Token: your-token; Another-Token: your-another-token} 61 | in Racket: 62 | @racketinput[ 63 | (http-get httpbin-org/anthing 64 | #:path "/fruits" 65 | #:data (hasheq 'color "red") 66 | #:headers (hasheq 'Another-Token "your-another-token")) 67 | ] 68 | 69 | and the preceding code is supported to be written in another way like below: 70 | @racketinput[ 71 | (http-bin-org/anthing 'get 72 | #:path "/fruits" 73 | #:data (hasheq 'color "red") 74 | #:headers (hasheq 'Another-Token "your-another-token")) 75 | ]} 76 | 77 | @item{Do a POST request like 78 | @commandline|{ 79 | curl -X GET https://httpbin.org/anything/fruits 80 | --header "Content-Type: application/application/x-www-form-urlencoded" 81 | --header "Token: your-overwritten-token" 82 | -d '{"make-in": "China", "price": "10", "color": "red"}' 83 | }| 84 | in Raket: 85 | @racketinput[ 86 | (http-post httpbin-org/anthing 87 | #:path "/fruits" 88 | #:data (hasheq 'color "red") 89 | #:headers (hasheq 'Content-Type "application/x-www-form-urlencoded" 'Token "your-overwritten-token")) 90 | ]} 91 | 92 | @item{Do a POST request with copying and modifying the predefined @racket[http-connection]'s headers to 93 | @litchar{Content-Type: application/x-www-form-urlencoded}: 94 | @racketinput[ 95 | (define new-conn 96 | (struct-copy http-connection httpbin-org/anthing 97 | [headers (hasheq 'Content-Type "application/x-www-form-urlencoded")])) 98 | ] 99 | @racketinput[ 100 | (http-post new-conn) 101 | ] 102 | } 103 | ] 104 | 105 | @; (code:line 106 | @; (define res (http-post "https://httpbin.org/anything" 107 | @; #:data (hasheq 'color "red"))) 108 | @; (http-response-body res) ;; the body of a response is auto converted to the racket type data unless you set @racket[current-http-response-auto]. 109 | @; ) 110 | 111 | @; (parameterize ([current-http-response-auto #f]) ;; set @racket[current-http-response-auto] to #f to get a raw format http response body. 112 | @; (define res (http-post "https://httpbin.org/anything" 113 | @; #:data (hasheq 'color "red"))) 114 | @; (http-response-body res)) 115 | @; ] 116 | 117 | 118 | @section{Reference} 119 | @subsection{Parameters} 120 | @defparam[current-http-client/user-agent v string? #:value "http-client[your-system-name/your-vm-sytem-type-name/your-racket-version]"]{ 121 | The user agent name used by requesting the HTTP servers. 122 | @history[#:added "1.0"] 123 | } 124 | 125 | @defparam[current-http-client/response-auto v boolean? #:value #t]{ 126 | Set this parameter to @racket[#f] to disable the auto convertion of the response's body data. 127 | In another word, @racket[http-response-body] of a @racket[http-response] will be a raw string if set this parameter to @racket[#f]. 128 | @history[#:changed "1.0" "renamed from current-http-response-auto"] 129 | } 130 | 131 | @defparam[current-http-client/pretty-print-depth v integer? #:value 1]{ 132 | This parameter is used by displaying structs of @racket[http-connection]/@racket[http-request]/@racket[http-response], check @racket[pretty-print-depth] for its implement details. 133 | @history[#:added "1.0"] 134 | @examples[#:eval (the-eval) 135 | (define conn1 136 | (http-connection "https://httpbin.org/anything" 137 | (hasheq 'Content-Type "application/json" 'Accept "application/json") 138 | (hasheq 'made-in "China" 'price 10))) 139 | 140 | (current-http-client/pretty-print-depth) 141 | conn1 142 | 143 | (current-http-client/pretty-print-depth 2) 144 | conn1 145 | ] 146 | } 147 | 148 | @defparam[current-http-client/debug v boolean? #:value #f]{ 149 | Show debug log or not. 150 | @history[#:added "1.0.1"] 151 | } 152 | 153 | @subsection{Structs} 154 | @margin-note{The displaying of HTTP client strcuts is controlled by @racket[current-http-client/pretty-print-depth].} 155 | 156 | @defstruct*[http-connection ([url string?] 157 | [headers hasheq] 158 | [data hasheq])]{ 159 | Construct a @racket[http-connection] instance and use it later by such as @racket[http-get] when you're requesting same website with nuance path/data/headers, check @secref["request-nuance-urls"] for usage examples. 160 | } 161 | 162 | @defstruct*[http-response ([request http-request?] 163 | [code number?] 164 | [headers hasheq] 165 | [body hasheq])]{ 166 | You will get a @racket[http-response] struct instance if you're doing a request such as using @racket[http-get]. 167 | } 168 | 169 | @defstruct*[http-request ([url string?] 170 | [method symbol?] 171 | [headers hasheq] 172 | [data hasheq])]{ 173 | Mostly, @racket[http-request] is included in the @racket[http-response] instance. 174 | } 175 | 176 | @subsection{Requests} 177 | @deftogether[( 178 | @defproc[(http-get [conn (or/c string? http-connection?)] 179 | [#:path path string? ""] 180 | [#:data data hasheq (hasheq)] 181 | [#:headers headers hasheq (hasheq)]) 182 | http-response?] 183 | @defproc[(http-post [conn (or/c string? http-connection?)] 184 | [#:path path string? ""] 185 | [#:data data hasheq (hasheq)] 186 | [#:headers headers hasheq (hasheq)]) 187 | http-response?] 188 | @defproc[(http-head [conn (or/c string? http-connection?)] 189 | [#:path path string? ""] 190 | [#:data data hasheq (hasheq)] 191 | [#:headers headers hasheq (hasheq)]) 192 | http-response?] 193 | @defproc[(http-options [conn (or/c string? http-connection?)] 194 | [#:path path string? ""] 195 | [#:data data hasheq (hasheq)] 196 | [#:headers headers hasheq (hasheq)]) 197 | http-response?] 198 | @defproc[(http-put [conn (or/c string? http-connection?)] 199 | [#:path path string? ""] 200 | [#:data data hasheq (hasheq)] 201 | [#:headers headers hasheq (hasheq)]) 202 | http-response?] 203 | @defproc[(http-delete [conn (or/c string? http-connection?)] 204 | [#:path path string? ""] 205 | [#:data data hasheq (hasheq)] 206 | [#:headers headers hasheq (hasheq)]) 207 | http-response?] 208 | @defproc[(http-patch [conn (or/c string? http-connection?)] 209 | [#:path path string? ""] 210 | [#:data data hasheq (hasheq)] 211 | [#:headers headers hasheq (hasheq)]) 212 | http-response?] 213 | )]{ 214 | Procedures to do the http requests. 215 | } 216 | 217 | @defproc[(http-do [method symbol?] [conn http-connection?] 218 | [#:data data hasheq (hasheq)] 219 | [#:path path string? ""] 220 | [#:headers headers hasheq (hasheq)]) 221 | http-response?]{ 222 | The low level function to do the http requests. 223 | } 224 | 225 | 226 | 227 | @section{Others} 228 | @subsection{Bug Report} 229 | Please go to github and create an issue for this repo. 230 | 231 | @subsection{TODOs} 232 | @itemlist[ 233 | @item{make @litchar{#} if it's too long.} 234 | @item{global param of debug mode to show request and response log msg just like the ruby faraday.} 235 | @item{make param of hasheq can also be alist and dict data.} 236 | ] 237 | 238 | @subsection{Change Logs} 239 | @itemlist[ 240 | @item{define a global param for pretty-print-depth for write-proc to show customized depth. --2021/02/26} 241 | @item{fix get urls with params will raise error and enhance docs. --2021/02/26} 242 | @item{fix additional / and ? added in the url sometimes. --2024/06/26} 243 | @item{show debug log. --2024/06/26} 244 | ] 245 | --------------------------------------------------------------------------------