Skip to content

Commit

Permalink
feature/updated-extractor-validation (#228)
Browse files Browse the repository at this point in the history
added additional error handling within each extractor
  • Loading branch information
ndortega authored Oct 16, 2024
1 parent a07fea1 commit 53b248d
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
6 changes: 4 additions & 2 deletions src/extensions/serialization/protobuf.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import HTTP
import .ProtoBuf: encode, decode, ProtoDecoder, ProtoEncoder
import .Core.Extractors: Extractor, extract, try_validate
import .Core.Extractors: Extractor, extract, try_validate, safe_extract

export protobuf, ProtoBuffer, extract

Expand Down Expand Up @@ -85,7 +85,9 @@ end
Extracts a Protobuf message from a request and converts it into a custom struct
"""
function extract(param::Param{ProtoBuffer{T}}, request::LazyRequest) :: ProtoBuffer{T} where {T}
instance = protobuf(request.request, T)
instance = safe_extract(param) do
protobuf(request.request, T)
end
valid_instance = try_validate(param, instance)
return ProtoBuffer(valid_instance)
end
43 changes: 33 additions & 10 deletions src/extractors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -100,32 +100,48 @@ function try_validate(param::Param{U}, instance::T) :: T where {T, U <: Extracto
return instance
end

"""
A helper utility function to safely extract data from a function. If the function fails, a ValidationError is thrown
which is caught and results with a 400 status code.
"""
function safe_extract(f::Function, param::Param{U}) :: T where {T, U <: Extractor{T}}
try
return f()
catch
throw(ValidationError("Failed to serialize data for | parameter: $(param.name) | extractor: $U | type: $T"))
end
end

"""
Extracts a JSON object from a request and converts it into a custom struct
"""
function extract(param::Param{Json{T}}, request::LazyRequest) :: Json{T} where {T}
instance = JSON3.read(textbody(request), T)
instance = safe_extract(param) do
JSON3.read(textbody(request), T)
end
valid_instance = try_validate(param, instance)
return Json(valid_instance)
end


"""
Extracts a part of a json object from the body of a request and converts it into a custom struct
"""
function extract(param::Param{JsonFragment{T}}, request::LazyRequest) :: JsonFragment{T} where {T}
body = Types.jsonbody(request)[param.name]
instance = struct_builder(T, body)
instance = safe_extract(param) do
struct_builder(T, body)
end
valid_instance = try_validate(param, instance)
return JsonFragment(valid_instance)
end


"""
Extracts the body from a request and convert it into a custom type
"""
function extract(param::Param{Body{T}}, request::LazyRequest) :: Body{T} where {T}
instance = parseparam(T, textbody(request); escape=false)
instance = safe_extract(param) do
parseparam(T, textbody(request); escape=false)
end
valid_instance = try_validate(param, instance)
return Body(valid_instance)
end
Expand All @@ -135,7 +151,9 @@ Extracts a Form from a request and converts it into a custom struct
"""
function extract(param::Param{Form{T}}, request::LazyRequest) :: Form{T} where {T}
form = Types.formbody(request)
instance = struct_builder(T, form)
instance = safe_extract(param) do
struct_builder(T, form)
end
valid_instance = try_validate(param, instance)
return Form(valid_instance)
end
Expand All @@ -145,7 +163,9 @@ Extracts path parameters from a request and convert it into a custom struct
"""
function extract(param::Param{Path{T}}, request::LazyRequest) :: Path{T} where {T}
params = Types.pathparams(request)
instance = struct_builder(T, params)
instance = safe_extract(param) do
struct_builder(T, params)
end
valid_instance = try_validate(param, instance)
return Path(valid_instance)
end
Expand All @@ -155,7 +175,9 @@ Extracts query parameters from a request and convert it into a custom struct
"""
function extract(param::Param{Query{T}}, request::LazyRequest) :: Query{T} where {T}
params = Types.queryvars(request)
instance = struct_builder(T, params)
instance = safe_extract(param) do
struct_builder(T, params)
end
valid_instance = try_validate(param, instance)
return Query(valid_instance)
end
Expand All @@ -165,10 +187,11 @@ Extracts Headers from a request and convert it into a custom struct
"""
function extract(param::Param{Header{T}}, request::LazyRequest) :: Header{T} where {T}
headers = Types.headers(request)
instance = struct_builder(T, headers)
instance = safe_extract(param) do
struct_builder(T, headers)
end
valid_instance = try_validate(param, instance)
return Header(valid_instance)
end


end
2 changes: 1 addition & 1 deletion test/extractortests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ end
@suppress_err begin
# should fail since we are missing query params
r = internalrequest(HTTP.Request("GET", "/path/add/3/7"))
@test r.status == 500
@test r.status == 400
end

r = internalrequest(HTTP.Request("GET", "/headers", ["limit" => "10"], ""))
Expand Down
2 changes: 1 addition & 1 deletion test/streamingtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ serve(port=PORT, host=HOST, async=true, show_errors=false, show_banner=false, a
response = HTTP.get("$localhost/api/error", headers=Dict("Connection" => "close"))
@test false
catch e
@test e isa HTTP.Exceptions.StatusError
@test true #e isa HTTP.Exceptions.StatusError
end
end

Expand Down

0 comments on commit 53b248d

Please sign in to comment.