-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathopenapi.rkt
More file actions
178 lines (155 loc) · 5.35 KB
/
openapi.rkt
File metadata and controls
178 lines (155 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#lang typed/racket/base
(provide file->openapi
(struct-out API)
(struct-out Route)
(struct-out Response)
(struct-out Param))
(require typed/json
racket/list
typed/net/url
"json-schema.rkt"
"utils.rkt")
(define-type Method (U 'get 'head 'post 'put 'delete))
(: method? (-> Any Boolean : Method))
(define (method? m)
(and (member m '(get head post put delete)) #t))
(struct API
([name : String]
[routes : (Listof Route)]
[hostname : String]
[ssl? : Boolean]
[path-prefix : String])
#:transparent)
(struct Route
([path : String]
[method : Method]
[security-requirement : (Option Security-Scheme)]
[body : (Listof Property)]
[parameters : (Listof Param)]
[responses : (Listof Response)])
#:transparent)
(define-type Param-In (U 'query 'path 'header 'cookie))
(struct Param
([name : Symbol]
[schema : Schema]
[in : Param-In])
#:transparent)
(struct Response
([schema : Schema-Object]
[code : Symbol])
#:transparent)
(define-type Security-Type (U 'apiKey 'http 'oauth2 'openIdConnect))
(define-type Security-In (U 'query 'header 'cookie))
(struct Security-Scheme
([type : Security-Type]
[in : Security-In])
#:transparent)
;; TODO: Write macro for the following functions
(define (string->Param-In [in : String]) : Param-In
(case in
[("path") 'path]
[("header") 'header]
[("query") 'query]
[("cookie") 'cookie]
[else (error (format "Expected one of 'query', 'path', 'header', 'cookie. Given ~a"
in))]))
(define (string->Security-Type [in : String]) : Security-Type
(case in
[("apiKey") 'apiKey]
[("http") 'http]
[("oauth2") 'oauth2]
[("openIdConnect") 'openIdConnect]
[else (error (format "Expected one of 'apiKey', 'http', 'oauth2', 'openIdConnect'. Given ~a"
in))]))
(define (string->Security-In [in : String]) : Security-In
(case in
[("query") 'query]
[("header") 'header]
[("cookie") 'cookie]
[else (error (format "Expected one of 'query', 'header', 'cookie'. Given ~a"
in))]))
(define (make-param [param : JSExpr] [top : JSExpr]) : Param
(cond
[(json-has-key? param '$ref)
(make-param (trace-ref (assert (json-ref param '$ref) string?) top) top)]
[else
(define name (string->symbol (assert (json-ref param 'name) string?)))
(define schema-json (json-ref param 'schema))
(define schema (make-schema-with-name name schema-json top))
(define param-in (string->Param-In (assert (json-ref param 'in) string?)))
(Param name schema param-in)]))
(define schema-keys '(content application/json schema))
(define (make-request-body [request : JSExpr]
[top : JSExpr]) : (Listof Property)
(cond
[(json-has-keys? request schema-keys)
(make-properties (json-ref (json-refs request schema-keys) 'properties) top)]
[else '()]))
(define (make-response [code : Symbol]
[method : Method]
[path : Symbol]
[response : JSExpr]
[top : JSExpr]) : Response
(define schema-name (string->symbol (format "~a-~a-~a" method path code)))
(define schema
(if (json-has-keys? response schema-keys)
(make-schema-with-name schema-name (json-refs response schema-keys) top)
(Schema-Object schema-name '())))
(Response (assert schema Schema-Object?) code))
(define (make-routes-for-path [path : Symbol]
[contents : JSExpr]
[top : JSExpr]) : (Listof Route)
(hash-map
(assert contents hash?)
(λ ([method : Symbol] [body : JSExpr])
(with-asserts ([method method?])
(define parameters
(map
(λ ([p : JSExpr]) (make-param p top))
(assert (json-ref body 'parameters '()) list?)))
(define responses : (Listof Response)
(for/list ([(code response-body)
(in-hash (assert (json-ref body 'responses) hash?))])
(make-response code method path response-body top)))
(define request-body
(make-request-body (json-ref body 'requestBody (hash)) top))
(Route
(symbol->string path)
method
#f ; Security not implemented
request-body
parameters
responses)))))
(define (make-routes [paths : JSExpr] [top : JSExpr])
(define routes : (Listof (Listof Route))
(for/list ([(path contents) (in-hash (assert paths hash?))])
(make-routes-for-path path contents top)))
(append* routes))
(define (parse-openapi [contents : JSExpr])
(define name (assert (json-refs contents '(info title)) string?))
(define routes (make-routes (json-ref contents 'paths) contents))
(define url
(string->url
(assert
(json-ref
(car (assert (json-ref contents 'servers) list?))
'url)
string?)))
(define path-prefix
(foldl
(λ ([e : path/param] [acc : String])
(string-append acc "/" (assert (path/param-path e) string?)))
""
(url-path url)))
(define ssl? (string=? (assert (url-scheme url) string?) "https"))
(API
name
routes
(assert (url-host url) string?)
ssl?
path-prefix))
(define (file->openapi [filename : String])
(with-input-from-file filename
(λ ()
(define contents (cast (read-json) JSExpr))
(parse-openapi contents))))