Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged: type converters, dynamic image plots, dates/datetimes, open api object schema types, multiline comments, multipart form fix #905

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f2b97b4
First attempt at converting parameters
slodge Nov 29, 2022
befc866
Possible changes for Dates and DateTimes
slodge Nov 29, 2022
184ed3d
fixes for slightly broken option tests
slodge Nov 29, 2022
0715efb
fix for slightly broken shared secret test
slodge Nov 29, 2022
4adc544
endpoint argument conversion tests
slodge Nov 29, 2022
386d201
Small fixes to help some existing endpoint test pass
slodge Nov 29, 2022
bd7200e
Typo
slodge Nov 29, 2022
cafc91e
replacing for loops with Map
slodge Nov 29, 2022
4357c92
Update R/openapi-types.R
slodge Nov 29, 2022
536dd29
for discussion
slodge Dec 2, 2022
ae091eb
further fixes/improvements to the apiTypes changes - most tests working
slodge Dec 2, 2022
ec7bb8c
number -> double in test - should be OK change
slodge Dec 3, 2022
5478c4e
fixed up more date/datetime PR issues - tests, lubridate isolation, more
slodge Dec 3, 2022
8f7242c
First attempt at adding schema objects for req+res bodies
slodge Dec 4, 2022
77901fd
Dynamic Parameters (third attempt at getting my github user account c…
slodge Jan 4, 2023
4c9a87a
missed some serializer params
slodge Jan 4, 2023
0fff338
Apply suggestions from code review
schloerke Jan 5, 2023
9b10172
Apply suggestions from code review
schloerke Jan 5, 2023
c16cd62
Apply suggestions from code review
schloerke Jan 5, 2023
7892856
Update comment
schloerke Jan 5, 2023
d0794e8
Merge branch 'main' into typedEndpointParameters
schloerke Jan 5, 2023
1240104
Merge branch 'datesAdded' into typedEndpointParameters
slodge Feb 22, 2023
ee7f753
Small fix
slodge Feb 22, 2023
b5b26a2
Merge branch 'dynamic_plots' into typedEndpointParameters
slodge Feb 22, 2023
0ed5bac
Merge branch 'openApiObjects' into typedEndpointParameters
slodge Feb 22, 2023
a98ba0a
Docs updates
slodge Feb 22, 2023
50a07b7
change requested for object to schema
slodge Feb 22, 2023
f0e37b8
Fix problems for quoted boundary strings
slodge Nov 10, 2023
20672a0
Merge pull request #1 from slodge/ideasMerged
slodge Nov 10, 2023
cef9014
Fix for file/binary api types in swagger
slodge Nov 13, 2023
25e1a24
Merge pull request #2 from slodge/ideasMerged
slodge Nov 13, 2023
1e9bc66
Updated error message
slodge Nov 13, 2023
7f05924
Assemble comment blocks for interim lines
slodge Nov 14, 2023
476c93e
multiline support in @apiTitle and friends
slodge Nov 15, 2023
0c8bd11
Multiline support in params and responses too - regex changes
slodge Nov 15, 2023
b6d1379
add verbose parsing as option (could be more verbose!)
slodge Nov 15, 2023
1308490
update to roxygen docs
slodge Nov 15, 2023
0db7d43
Merge pull request #3 from slodge/multilineComments
slodge Nov 15, 2023
7aab515
Merge pull request #4 from slodge/main
slodge Nov 15, 2023
5289828
Change print to message in error logs
slodge-work Nov 17, 2023
0b8f696
Merge pull request #5 from slodge/main
slodge-work Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ Suggests:
geojsonsf,
redoc,
rapidoc,
sf
RoxygenNote: 7.2.2
sf,
lubridate
RoxygenNote: 7.2.3
Collate:
'async.R'
'content-types.R'
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export(pr_head)
export(pr_hook)
export(pr_hooks)
export(pr_mount)
export(pr_object)
export(pr_post)
export(pr_put)
export(pr_run)
Expand Down
2 changes: 1 addition & 1 deletion R/default-handlers.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ default404Handler <- function(req, res) {

defaultErrorHandler <- function(){
function(req, res, err){
print(err)
message(err)

li <- list()

Expand Down
121 changes: 105 additions & 16 deletions R/openapi-spec.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@

objectSpecification <- function(object) {
spec <- list(type = "object")

if (length(object$props) > 0) {
properties <- propertiesSpecification(object$props)
spec$properties <- properties
}

ret <- list()
ret[[object$name]] <- spec
ret
}

#' Convert the endpoints as they exist on the Plumber object to a list which can
#' be converted into a OpenAPI Specification for these endpoints
Expand All @@ -17,9 +29,28 @@ endpointSpecification <- function(routerEndpointEntry, path = routerEndpointEntr
funcParams <- routerEndpointEntry$getFuncParams()
# Get the plumber decoration defined endpoint params
endpointParams <- routerEndpointEntry$getEndpointParams()

# if legacy plumber.staticSerializers is specified then ignore all req serializer
# based parameters
if (getOption("plumber.staticSerializers", default="FALSE") == "TRUE") {
serializerParams <- list()
} else {
# Get the plumber serializer defined endpoint params
serializerParams <- routerEndpointEntry$getSerializerParams()
}

for (verb in routerEndpointEntry$verbs) {
params <- parametersSpecification(endpointParams, pathParams, funcParams)
params <- parametersSpecification(endpointParams, pathParams, funcParams, serializerParams)

if (!is.null(routerEndpointEntry$requestBodyObjectName)) {
if (length(params$requestBody) != 0L) {
# TODO - what sort of warning or stop to fire?
warning("params$requestBody already set - ignoring the requestBodyObjectName ", routerEndpointEntry$requestBodyObjectName)
} else {
params$requestBody$content$`application/json`[["schema"]][["$ref"]] <-
paste0("#/components/schemas/", routerEndpointEntry$requestBodyObjectName)
}
}
# If we haven't already documented a path param, we should add it here.
# FIXME: warning("Undocumented path parameters: ", paste0())

Expand Down Expand Up @@ -52,6 +83,7 @@ defaultResponse <- list(
description = "Default response."
)
)

responsesSpecification <- function(endpts){
if (!inherits(endpts, "PlumberEndpoint")) {
return(defaultResponse)
Expand All @@ -78,18 +110,67 @@ responsesSpecification <- function(endpts){
resps
}

#' Extract the OpenAPI properties Specification from the object
#' properties.
#' @noRd
propertiesSpecification <- function(props) {
output <- list()

for (key in unique(names(props))) {
prop <- props[[key]]
type <- prop$type

if (is.null(apiTypesInfo[[type]])) {
warning("Unknown property type ", type, " for ", key," - defaulting to ", defaultApiType)
type <- defaultApiType
}

typeInfo <- apiTypesInfo[[type]]

property <- list(
type = type,
format = typeInfo$format,
description = prop$desc,
required = prop$required
)

objectName <- prop$objectName
if (type == "object" && !is.null(objectName)) {
property$type <- NULL
property$format <- NULL
property[["$ref"]] <- paste0("#/components/schemas/", objectName)
}

if (prop$isArray) {
property$items <- list(
type = property$type,
format = property$format,
properties = property$properties,
"$ref" = property[["$ref"]]
)
property$type <- "array"
property$format <- NULL
property$properties <- NULL
property[["$ref"]] <- NULL
}
output[[key]] = property
}

output
}

#' Extract the OpenAPI parameters Specification from the endpoint
#' paramters.
#' @noRd
parametersSpecification <- function(endpointParams, pathParams, funcParams = NULL){
parametersSpecification <- function(endpointParams, pathParams, funcParams = NULL, serializerParams = NULL){

params <- list(
parameters = list(),
requestBody = NULL
)
inBody <- filterApiTypes("requestBody", "location")
inRaw <- filterApiTypes("binary", "format")
for (p in unique(c(names(endpointParams), pathParams$name, names(funcParams)))) {
inRaw <- filterApiTypes("binary", "openApiFormat")
for (p in unique(c(names(endpointParams), pathParams$name, names(funcParams), names(serializerParams)))) {

# Dealing with priorities endpointParams > pathParams > funcParams
# For each p, find out which source to trust for :
Expand All @@ -112,27 +193,34 @@ parametersSpecification <- function(endpointParams, pathParams, funcParams = NUL
type <- priorizeProperty(defaultApiType,
pathParams[pathParams$name == p,]$type,
endpointParams[[p]]$type,
funcParams[[p]]$type)
funcParams[[p]]$type,
serializerParams[[p]]$type)
type <- plumberToApiType(type, inPath = TRUE)
isArray <- priorizeProperty(defaultIsArray,
pathParams[pathParams$name == p,]$isArray,
endpointParams[[p]]$isArray,
funcParams[[p]]$isArray)
funcParams[[p]]$isArray,
serializerParams[[p]]$isArray)
} else {
location <- "query"
style <- "form"
explode <- TRUE
type <- priorizeProperty(defaultApiType,
endpointParams[[p]]$type,
funcParams[[p]]$type)
funcParams[[p]]$type,
serializerParams[[p]]$type)
type <- plumberToApiType(type)
isArray <- priorizeProperty(defaultIsArray,
endpointParams[[p]]$isArray,
funcParams[[p]]$isArray)
funcParams[[p]]$isArray,
serializerParams[[p]]$isArray)
required <- priorizeProperty(funcParams[[p]]$required,
endpointParams[[p]]$required)
endpointParams[[p]]$required,
serializerParams[[p]]$required)
}

desc <- endpointParams[[p]]$desc %||% serializerParams[[p]]$desc

# Building OpenAPI Specification
if (type %in% inBody) {
if (length(params$requestBody) == 0L) {
Expand All @@ -147,12 +235,13 @@ parametersSpecification <- function(endpointParams, pathParams, funcParams = NUL
)
if (type %in% inRaw) {
names(params$requestBody$content) <- "multipart/form-data"
property$type <- apiTypesInfo[[type]]$realType
property$type <- apiTypesInfo[[type]]$openApiType
property$format <- apiTypesInfo[[type]]$openApiFormat
property$example <- NULL
}
if (isArray) {
property$items <- list(
type = property$type,
type = apiTypesInfo[[type]]$openApiType,
format = property$format,
example = property$example
)
Expand All @@ -166,21 +255,21 @@ parametersSpecification <- function(endpointParams, pathParams, funcParams = NUL
} else {
paramList <- list(
name = p,
description = endpointParams[[p]]$desc,
description = desc,
`in` = location,
required = required,
schema = list(
type = type,
format = apiTypesInfo[[type]]$format,
type = apiTypesInfo[[type]]$openApiType,
format = apiTypesInfo[[type]]$openApiFormat,
default = funcParams[[p]]$default
)
)
if (isArray) {
paramList$schema <- list(
type = "array",
items = list(
type = type,
format = apiTypesInfo[[type]]$format
type = apiTypesInfo[[type]]$openApiType,
format = apiTypesInfo[[type]]$openApiFormat
),
default = funcParams[[p]]$default
)
Expand Down
Loading