Skip to content

Commit d58848e

Browse files
authored
Switch requests to path first URLs (#122)
1 parent 8244042 commit d58848e

26 files changed

Lines changed: 351 additions & 378 deletions

Rlabkey/DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: Rlabkey
2-
Version: 3.4.4
3-
Date: 2025-09-16
2+
Version: 3.4.5
3+
Date: 2026-01-20
44
Title: Data Exchange Between R and 'LabKey' Server
55
Authors@R: c(person(given = "Peter",
66
family = "Hussey",

Rlabkey/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Changes in 3.4.5
2+
o Switch to using path first URLs for LabKey server requests.
3+
o Utilize httr to generate request query parameters.
4+
o labkey.makeFilter will produce a list of named elements using the asList parameter.
5+
16
Changes in 3.4.4
27
o Issue 53481: additional validation for assay run configurations.
38
o Improve validation when a zero-row dataframe is passed to insertRows/updateRows/deleteRows

Rlabkey/R/labkey.defaults.R

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ isWafEncoding <- function()
271271
return (.lkdefaults$wafEncode)
272272
}
273273

274-
275274
isRequestError <- function(response, status_code)
276275
{
277276
status_code <- getStatusCode(response)
@@ -357,4 +356,32 @@ encodeURIComponent <- function(value)
357356
value <- gsub("%28", "(", value)
358357
value <- gsub("%29", ")", value)
359358
return (value)
359+
}
360+
361+
# Construct a LabKey URL (path first format)
362+
labkey.buildURL <- function(baseUrl=NULL, controller, action, folderPath = NULL, parameters = NULL)
363+
{
364+
baseUrl=labkey.getBaseUrl(baseUrl)
365+
366+
# check required parameters
367+
if (missing(baseUrl) || missing(controller) || missing(action) || is.null(folderPath))
368+
stop (paste("A value must be specified for each of baseUrl, controller, action and folderPath."))
369+
370+
# normalize the folder path
371+
folderPath <- encodeFolderPath(folderPath)
372+
373+
myUrl <- paste(baseUrl, folderPath, controller, "-", action, sep="")
374+
375+
if (!is.null(parameters))
376+
{
377+
if (!is.list(parameters))
378+
stop (paste("parameters must be a list data structure."))
379+
380+
# add the parameters as a query string
381+
url <- parse_url(myUrl)
382+
url$query = parameters
383+
384+
myUrl <- build_url(url)
385+
}
386+
return (myUrl)
360387
}

Rlabkey/R/labkey.deleteRows.R

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ labkey.deleteRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
3030
if (!missing(options) & !is.list(options))
3131
stop (paste("The options parameter must be a list data structure."))
3232

33-
## normalize the folder path
34-
folderPath <- encodeFolderPath(folderPath)
35-
3633
## URL encode folder path, JSON encode post body (if not already encoded)
3734
toDelete <- convertFactorsToStrings(toDelete);
3835

@@ -43,8 +40,7 @@ labkey.deleteRows <- function(baseUrl=NULL, folderPath, schemaName, queryName, t
4340
params <- c(params, options)
4441

4542
pbody <- jsonEncodeRowsAndParams(toDelete, params, NULL)
46-
47-
myurl <- paste(baseUrl, "query", folderPath, "deleteRows.api", sep="")
43+
myurl <- labkey.buildURL(baseUrl, "query", "deleteRows.api", folderPath)
4844

4945
## Execute via our standard POST function
5046
mydata <- labkey.post(myurl, pbody)
@@ -65,10 +61,7 @@ labkey.truncateTable <- function(baseUrl=NULL, folderPath, schemaName, queryName
6561
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
6662
if (missing(queryName)) stop (paste("A value must be specified for queryName."))
6763

68-
## normalize the folder path
69-
folderPath <- encodeFolderPath(folderPath)
70-
71-
url <- paste(baseUrl, "query", folderPath, "truncateTable.api", sep="")
64+
url <- labkey.buildURL(baseUrl, "query", "truncateTable.api", folderPath)
7265

7366
params <- list(schemaName=schemaName, queryName=queryName)
7467
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))

Rlabkey/R/labkey.domain.R

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ labkey.domain.get <- function(baseUrl=NULL, folderPath, schemaName, queryName)
2424
if(missing(baseUrl) || is.null(baseUrl) || missing(folderPath) || missing(schemaName) || missing(queryName))
2525
stop (paste("A value must be specified for each of baseUrl, folderPath, schemaName and queryName."))
2626

27-
## normalize the folder path
28-
folderPath <- encodeFolderPath(folderPath)
29-
30-
url <- paste(baseUrl, "property", folderPath, "getDomain.api", sep="")
31-
27+
url <- labkey.buildURL(baseUrl, "property", "getDomain.api", folderPath)
3228
params <- list(schemaName=schemaName, queryName=queryName)
3329
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
3430

@@ -63,11 +59,9 @@ labkey.domain.save <- function(baseUrl=NULL, folderPath, schemaName, queryName,
6359
if (!is.list(domainDesign))
6460
stop (paste("domainDesign must be a list data structure."))
6561

66-
## normalize the folder path
67-
folderPath <- encodeFolderPath(folderPath)
6862
params <- list(schemaName = schemaName, queryName = queryName, domainDesign = domainDesign)
63+
url <- labkey.buildURL(baseUrl, "property", "saveDomain.api", folderPath)
6964

70-
url <- paste(baseUrl, "property", folderPath, "saveDomain.api", sep="")
7165
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
7266

7367
return (fromJSON(response))
@@ -157,10 +151,7 @@ labkey.domain.create <- function(baseUrl=NULL, folderPath, domainKind=NULL, doma
157151
createDomain = createDomain, importData = importData)
158152
}
159153

160-
## normalize the folder path
161-
folderPath <- encodeFolderPath(folderPath)
162-
163-
url <- paste(baseUrl, "property", folderPath, "createDomain.api", sep="")
154+
url <- labkey.buildURL(baseUrl, "property", "createDomain.api", folderPath)
164155
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
165156

166157
return (fromJSON(response))
@@ -175,11 +166,7 @@ labkey.domain.drop <- function(baseUrl=NULL, folderPath, schemaName, queryName)
175166
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
176167
if (missing(queryName)) stop (paste("A value must be specified for queryName."))
177168

178-
## normalize the folder path
179-
folderPath <- encodeFolderPath(folderPath)
180-
181-
url <- paste(baseUrl, "property", folderPath, "deleteDomain.api", sep="")
182-
169+
url <- labkey.buildURL(baseUrl, "property", "deleteDomain.api", folderPath)
183170
params <- list(schemaName=schemaName, queryName=queryName)
184171
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
185172

@@ -194,17 +181,14 @@ labkey.domain.inferFields <- function(baseUrl=NULL, folderPath, df)
194181
if (missing(baseUrl) || is.null(baseUrl) || missing(folderPath) || missing(df))
195182
stop (paste("A value must be specified for each of baseUrl, folderPath and df."))
196183

197-
## normalize the folder path
198-
folderPath <- encodeFolderPath(folderPath)
199-
200184
## write the dataframe to a tempfile to post to the server
201185
tf <- tempfile(fileext=".tsv")
202186
write.table(df, file=tf, sep="\t", quote=FALSE, row.names=FALSE)
203187

204188
## Execute via our standard POST function
205-
url <- paste(baseUrl, "property", folderPath, "inferDomain.api", sep="")
206-
189+
url <- labkey.buildURL(baseUrl, "property", "inferDomain.api", folderPath)
207190
rawdata <- labkey.post(url, list(file=upload_file(tf)), encoding="multipart")
191+
208192
## delete the temp file
209193
file.remove(tf)
210194
response <- fromJSON(rawdata)

Rlabkey/R/labkey.executeSql.R

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ labkey.executeSql <- function(baseUrl=NULL, folderPath, schemaName, sql, maxRows
2525
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
2626
if (missing(sql)) stop (paste("A value must be specified for sql."))
2727

28-
## normalize the folder path
29-
folderPath <- encodeFolderPath(folderPath)
30-
3128
## Construct url
32-
myurl <- paste(baseUrl, "query", folderPath, "executeSql.api", sep="")
29+
myurl <- labkey.buildURL(baseUrl, "query", "executeSql.api", folderPath)
3330

3431
## Apply wafEncode, if requested
3532
if (isWafEncoding()) sql <- wafEncode(sql)

Rlabkey/R/labkey.experiment.R

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,8 @@ labkey.experiment.saveBatch <- function(baseUrl=NULL, folderPath, assayConfig =
156156
if (is.null(assayConfig) && is.null(protocolName))
157157
stop (paste("Either an assay config list or protocolName must be specified. The assay configuration must contain either an assayId or both assayName and providerName"))
158158

159-
## normalize the folder path
160-
folderPath <- encodeFolderPath(folderPath)
161-
162159
## Now post form with batch object filled out
163-
url <- paste(baseUrl, "assay", folderPath, "saveAssayBatch.api", sep="")
160+
url <- labkey.buildURL(baseUrl, "assay", "saveAssayBatch.api", folderPath)
164161

165162
if (!is.null(assayConfig))
166163
params = assayConfig
@@ -185,11 +182,8 @@ labkey.experiment.saveRuns <- function(baseUrl=NULL, folderPath, protocolName, r
185182
if (missing(protocolName)) stop (paste("A value must be specified for protocolName."))
186183
if (missing(runList)) stop (paste("A value must be specified for runList."))
187184

188-
## normalize the folder path
189-
folderPath <- encodeFolderPath(folderPath)
190-
191185
## Now post form with runs object filled out
192-
url <- paste(baseUrl, "assay", folderPath, "saveAssayRuns.api", sep="")
186+
url <- labkey.buildURL(baseUrl, "assay", "saveAssayRuns.api", folderPath)
193187

194188
if (!is.null(runList))
195189
{
@@ -234,10 +228,7 @@ labkey.experiment.lineage <- function(baseUrl=NULL, folderPath, lsids, options =
234228
if (!missing(options))
235229
params <- c(params, options)
236230

237-
## normalize the folder path
238-
folderPath <- encodeFolderPath(folderPath)
239-
240-
url <- paste(baseUrl, "experiment", folderPath, "lineage.api", sep="")
231+
url <- labkey.buildURL(baseUrl, "experiment", "lineage.api", folderPath)
241232
response <- labkey.post(url, toJSON(params, auto_unbox=TRUE))
242233

243234
return (fromJSON(response, simplifyVector=FALSE, simplifyDataFrame=FALSE))

Rlabkey/R/labkey.getFolders.R

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,33 @@ labkey.getFolders <- function(baseUrl=NULL, folderPath, includeEffectivePermissi
2626
folderPath <- encodeFolderPath(folderPath)
2727

2828
## Formatting
29-
if(includeSubfolders) {inclsf <- paste("1&depth=", depth, sep="")} else {inclsf <- "0"}
30-
if(includeEffectivePermissions) {inclep <- "1"} else {inclep <- "0"}
31-
if(includeChildWorkbooks) {inclcw <- "1"} else {inclcw <- "0"}
29+
params <- list()
30+
if (includeSubfolders)
31+
params <- c(params, list("includeSubfolders"=1, "depth"=depth))
32+
else
33+
params <- c(params, list("includeSubfolders"=0))
34+
35+
if (includeEffectivePermissions)
36+
params <- c(params, list("includeEffectivePermissions"=1))
37+
else
38+
params <- c(params, list("includeEffectivePermissions"=0))
39+
40+
if (includeChildWorkbooks)
41+
params <- c(params, list("includeChildWorkbooks"=1))
42+
else
43+
params <- c(params, list("includeChildWorkbooks"=0))
3244

33-
inclsp <- "0"
3445
resultCols = c("name", "path", "id", "effectivePermissions")
35-
if(includeStandardProperties) {
36-
inclsp <- "1"
46+
if (includeStandardProperties)
47+
{
48+
params <- c(params, list("includeStandardProperties"=1))
3749
resultCols = c("name", "path", "id", "title", "type", "folderType", "effectivePermissions")
3850
}
51+
else
52+
params <- c(params, list("includeStandardProperties"=0))
3953

4054
## Construct url
41-
myurl <- paste(baseUrl,"project",folderPath,"getContainers.view?","includeSubfolders=",inclsf,
42-
"&includeEffectivePermissions=",inclep,"&includeChildWorkbooks=",inclcw,"&includeStandardProperties=",inclsp,
43-
sep="")
55+
myurl <- labkey.buildURL(baseUrl, "project", "getContainers.api", folderPath, params)
4456

4557
## Execute via our standard GET function
4658
mydata <- labkey.get(myurl);

Rlabkey/R/labkey.getQueryInfo.R

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,14 @@ getQueryInfo <- function(baseUrl=NULL, folderPath, schemaName, queryName, showDe
4747
if (missing(folderPath)) stop (paste("A value must be specified for folderPath."))
4848
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
4949
if (missing(queryName)) stop (paste("A value must be specified for queryName."))
50+
if (is.null(lookupKey)==FALSE) {char <- nchar(lookupKey); if(char<1) {lookupKey<-NULL} }
5051

51-
if(is.null(lookupKey)==FALSE) {char <- nchar(lookupKey); if(char<1) {lookupKey<-NULL} }
52-
53-
## URL encoding (if not already encoded)
54-
if(schemaName==URLdecode(schemaName)) {schemaName <- URLencode(schemaName)}
55-
if(queryName==URLdecode(queryName)) {queryName <- URLencode(queryName)}
56-
if(is.null(lookupKey)==FALSE) {if(lookupKey==URLdecode(lookupKey)) lookupKey <- URLencode(lookupKey)}
57-
58-
## normalize the folder path
59-
folderPath <- encodeFolderPath(folderPath)
52+
params <- list("schemaName"=schemaName, "query.queryName"=queryName, "apiVersion"="8.3")
53+
if (!is.null(lookupKey))
54+
params <- c(params, list("fk"=lookupKey))
6055

6156
## Construct url
62-
myurl <- paste(baseUrl,"query",folderPath,"getQueryDetails.api?schemaName=", schemaName, "&queryName=", queryName, "&apiVersion=8.3", sep="")
63-
if(is.null(lookupKey)==FALSE) {myurl <- paste(myurl,"&fk=",lookupKey,sep="")}
57+
myurl <- labkey.buildURL(baseUrl, "query", "getQueryDetails.api", folderPath, params)
6458

6559
## Execute via our standard GET function
6660
mydata <- labkey.get(myurl)

Rlabkey/R/labkey.getQueryLists.R

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,30 @@ labkey.getQueryViews <- function(baseUrl=NULL, folderPath, schemaName, queryName
3434
getQueryLists <- function(baseUrl=NULL, folderPath, schemaName, queryName=NULL)
3535
{
3636
baseUrl=labkey.getBaseUrl(baseUrl)
37-
if((length(queryName)>0) && (queryName==URLdecode(queryName)) ) { queryName <- URLencode(queryName) }
3837

3938
## Validate required parameters
4039
if (missing(folderPath)) stop (paste("A value must be specified for folderPath."))
4140
if (missing(schemaName)) stop (paste("A value must be specified for schemaName."))
4241

43-
## URL encoding of schemaName (if not already encoded)
44-
if(schemaName==URLdecode(schemaName)) {schemaName <- URLencode(schemaName)}
45-
46-
## normalize the folder path
47-
folderPath <- encodeFolderPath(folderPath)
42+
params <- list("schemaName"=schemaName, "apiVersion"="8.3")
4843

4944
## now setup the different columns for views vs queries
50-
if(length(queryName)==0)
45+
if (length(queryName)==0)
5146
{
52-
serverAction <- "getQueries.view?schemaName="
53-
qParam <- ""
47+
serverAction <- "getQueries.api"
5448
queryObjType <- "queries"
5549
columnNames <- c("queryName", "fieldName")
5650
}
5751
else
5852
{
59-
serverAction <- "getQueryViews.api?schemaName="
60-
qParam <- paste("&queryName=",queryName, sep="")
53+
serverAction <- "getQueryViews.api"
54+
params <- c(params, list("queryName"=queryName))
6155
queryObjType <- "views"
6256
columnNames <- c("viewName", "fieldName")
6357
}
6458

6559
## Construct url
66-
myurl <- paste(baseUrl, "query", folderPath, serverAction, schemaName, qParam, "&apiVersion=8.3", sep="")
60+
myurl <- labkey.buildURL(baseUrl, "query", serverAction, folderPath, params)
6761

6862
## Execute via our standard GET function
6963
mydata <- labkey.get(myurl);

0 commit comments

Comments
 (0)