-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathserver.jl
172 lines (151 loc) · 5.67 KB
/
server.jl
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
module Servers
using JSON
using HTTP
import ..OpenAPI: APIModel, ValidationException, from_json, to_json, deep_object_to_array, StyleCtx, is_deep_explode
function middleware(impl, read, validate, invoke;
init=nothing,
pre_validation=nothing,
pre_invoke=nothing,
post_invoke=nothing
)
handler = req -> (invoke(impl; post_invoke=post_invoke))(req)
if !isnothing(pre_invoke)
handler = pre_invoke(handler)
end
handler = validate(handler)
if !isnothing(pre_validation)
handler = pre_validation(handler)
end
handler = read(handler)
if !isnothing(init)
handler = init(handler)
end
return handler
end
##############################
# server parameter conversions
##############################
struct Param
keylist::Vector{String}
value::String
end
function parse_query_dict(query_dict::Dict{String, String})::Vector{Param}
params = Vector{Param}()
for (key, value) in query_dict
keylist = replace.(split(key, "["), "]"=>"")
push!(params, Param(keylist, value))
end
return params
end
function deep_dict_repr(qp::Dict)
params = parse_query_dict(qp)
deserialized_dict = Dict{String, Any}()
for param in params
current = deserialized_dict
for part in param.keylist[1:end-1]
current = get!(current, part) do
return Dict{String, Any}()
end
end
current[param.keylist[end]] = param.value
end
return deserialized_dict
end
function get_param(source::Dict, name::String, required::Bool)
val = get(source, name, nothing)
if required && isnothing(val)
throw(ValidationException("required parameter \"$name\" missing"))
end
return val
end
function get_param(source::Vector{HTTP.Forms.Multipart}, name::String, required::Bool)
ind = findfirst(x -> x.name == name, source)
if required && isnothing(ind)
throw(ValidationException("required parameter \"$name\" missing"))
elseif isnothing(ind)
return nothing
else
return source[ind]
end
end
function to_param_type(::Type{T}, strval::String; stylectx=nothing) where {T <: Number}
parse(T, strval)
end
to_param_type(::Type{T}, val::T; stylectx=nothing) where {T} = val
to_param_type(::Type{T}, ::Nothing; stylectx=nothing) where {T} = nothing
to_param_type(::Type{String}, val::Vector{UInt8}; stylectx=nothing) = String(copy(val))
to_param_type(::Type{Vector{UInt8}}, val::String; stylectx=nothing) = convert(Vector{UInt8}, copy(codeunits(val)))
to_param_type(::Type{Vector{T}}, val::Vector{T}, _collection_format::Union{String,Nothing}; stylectx=nothing) where {T} = val
to_param_type(::Type{Vector{T}}, json::Vector{Any}; stylectx=nothing) where {T} = [to_param_type(T, x; stylectx) for x in json]
function to_param_type(::Type{Vector{T}}, json::Dict{String, Any}; stylectx=nothing) where {T}
if !isnothing(stylectx) && is_deep_explode(stylectx)
cvt = deep_object_to_array(json)
if isa(cvt, Vector)
return to_param_type(Vector{T}, cvt; stylectx)
end
end
error("Unable to convert $json to $(Vector{T})")
end
function to_param_type(::Type{T}, strval::String; stylectx=nothing) where {T <: APIModel}
from_json(T, JSON.parse(strval); stylectx)
end
function to_param_type(::Type{T}, json::Dict{String,Any}; stylectx=nothing) where {T <: APIModel}
from_json(T, json; stylectx)
end
function to_param_type(::Type{Vector{T}}, strval::String, delim::String; stylectx=nothing) where {T}
elems = string.(strip.(split(strval, delim)))
return map(x->to_param_type(T, x; stylectx), elems)
end
function to_param_type(::Type{Vector{T}}, strval::String; stylectx=nothing) where {T}
elems = JSON.parse(strval)
return map(x->to_param_type(T, x; stylectx), elems)
end
function to_param(T, source::Dict, name::String; required::Bool=false, collection_format::Union{String,Nothing}=",", multipart::Bool=false, isfile::Bool=false, style::String="form", is_explode::Bool=true, location=:query)
deep_explode = style == "deepObject" && is_explode
if deep_explode
source = deep_dict_repr(source)
end
param = get_param(source, name, required)
if param === nothing
return nothing
end
if multipart
# param is a Multipart
param = isfile ? param.data : String(param.data)
end
if deep_explode
return to_param_type(T, param; stylectx=StyleCtx(location, style, is_explode))
end
if T <: Vector
to_param_type(T, param, collection_format)
else
to_param_type(T, param)
end
end
function to_param(T, source::Vector{HTTP.Forms.Multipart}, name::String; required::Bool=false, collection_format::Union{String,Nothing}=",", multipart::Bool=false, isfile::Bool=false)
param = get_param(source, name, required)
if param === nothing
return nothing
end
if multipart
# param is a Multipart
param = isfile ? take!(param.data) : String(take!(param.data))
end
if T <: Vector
return to_param_type(T, param, collection_format)
else
return to_param_type(T, param)
end
end
function HTTP.Response(code::Integer, o::APIModel)
return HTTP.Response(code, [Pair("Content-Type", "application/json")], to_json(o))
end
server_response(resp::HTTP.Response) = resp
server_response(::Nothing) = server_response("")
server_response(ret::Vector{UInt8}) =
HTTP.Response(200, ["Content-Type" => "application/octet-stream"], body=ret)
server_response(ret) =
server_response(to_json(ret), [Pair("Content-Type", "application/json")])
server_response(resp::AbstractString, headers=HTTP.Headers()) =
HTTP.Response(200, headers, body=resp)
end # module Servers