Skip to content

Commit

Permalink
feat: implement the header parameter "headers=false" to disable the h…
Browse files Browse the repository at this point in the history
…eader in the returned CSV/TSV #624
  • Loading branch information
fengelniederhammer committed Feb 2, 2024
1 parent eaa832c commit 24b9155
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ const val OFFSET_DESCRIPTION =
"""The offset of the first entry to return in the response.
This is useful for pagination in combination with \"limit\"."""
const val FORMAT_DESCRIPTION =
"""The data format of the response. Alternatively, the data format can be specified by setting the
\"Accept\"-header. When both are specified, this parameter takes precedence."""
"""The data format of the response.
Alternatively, the data format can be specified by setting the \"Accept\"-header.
You can include the parameter to return the CSV/TSV without headers: "$TEXT_CSV_WITHOUT_HEADERS_HEADER".
When both are specified, this parameter takes precedence."""

private const val MAYBE_DESCRIPTION = """
A mutation can be wrapped in a maybe expression "MAYBE(\<mutation\>)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface CsvRecord {
@Component
class CsvWriter {
fun write(
headers: Array<String>,
headers: Array<String>?,
data: List<CsvRecord>,
delimiter: Delimiter,
): String {
Expand All @@ -24,7 +24,11 @@ class CsvWriter {
CSVFormat.DEFAULT.builder()
.setRecordSeparator("\n")
.setDelimiter(delimiter.value)
.setHeader(*headers)
.also {
when {
headers != null -> it.setHeader(*headers)
}
}
.build(),
).use {
for (datum in data) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,21 @@ import java.util.Enumeration

private val log = KotlinLogging.logger {}

const val HEADERS_ACCEPT_HEADER_PARAMETER = "headers"

const val TEXT_CSV_HEADER = "text/csv"
const val TEXT_CSV_WITHOUT_HEADERS_HEADER = "text/csv;$HEADERS_ACCEPT_HEADER_PARAMETER=false"
const val TEXT_TSV_HEADER = "text/tab-separated-values"

const val DATA_FORMAT_FILTER_ORDER = 0

object DataFormat {
const val JSON = "JSON"
const val CSV = "CSV"
const val CSV_WITHOUT_HEADERS = "CSV-WITHOUT-HEADERS"
const val TSV = "TSV"
}

@Component
@Order(DATA_FORMAT_FILTER_ORDER)
class DataFormatParameterFilter(val objectMapper: ObjectMapper) : OncePerRequestFilter() {
Expand All @@ -40,25 +50,9 @@ class AcceptHeaderModifyingRequestWrapper(
) : HttpServletRequestWrapper(reReadableRequest) {
override fun getHeader(name: String): String? {
if (name.equals("Accept", ignoreCase = true)) {
when (reReadableRequest.getStringField(FORMAT_PROPERTY)?.uppercase()) {
"CSV" -> {
log.debug { "Overwriting Accept header to $TEXT_CSV_HEADER due to format property" }
return TEXT_CSV_HEADER
}

"TSV" -> {
log.debug { "Overwriting Accept header to $TEXT_TSV_HEADER due to format property" }
return TEXT_TSV_HEADER
}

"JSON" -> {
log.debug {
"Overwriting Accept header to ${MediaType.APPLICATION_JSON_VALUE} due to format property"
}
return MediaType.APPLICATION_JSON_VALUE
}

else -> {}
when (val overwrittenValue = findAcceptHeaderOverwriteValue()) {
null -> {}
else -> return overwriteWith(overwrittenValue)
}
}

Expand All @@ -67,28 +61,32 @@ class AcceptHeaderModifyingRequestWrapper(

override fun getHeaders(name: String): Enumeration<String>? {
if (name.equals("Accept", ignoreCase = true)) {
when (reReadableRequest.getStringField(FORMAT_PROPERTY)?.uppercase()) {
"CSV" -> {
log.debug { "Overwriting Accept header to $TEXT_CSV_HEADER due to format property" }
return Collections.enumeration(listOf(TEXT_CSV_HEADER))
}
when (val overwrittenValue = findAcceptHeaderOverwriteValue()) {
null -> {}
else -> return Collections.enumeration(listOf(overwriteWith(overwrittenValue)))
}
}

"TSV" -> {
log.debug { "Overwriting Accept header to $TEXT_TSV_HEADER due to format property" }
return Collections.enumeration(listOf(TEXT_TSV_HEADER))
}
return super.getHeaders(name)
}

"JSON" -> {
log.debug {
"Overwriting Accept header to ${MediaType.APPLICATION_JSON_VALUE} due to format property"
}
return Collections.enumeration(listOf(MediaType.APPLICATION_JSON_VALUE))
}
override fun getHeaderNames(): Enumeration<String> =
when (findAcceptHeaderOverwriteValue()) {
null -> super.getHeaderNames()
else -> Collections.enumeration(super.getHeaderNames().toList() + "Accept")
}

else -> {}
}
private fun findAcceptHeaderOverwriteValue() =
when (reReadableRequest.getStringField(FORMAT_PROPERTY)?.uppercase()) {
DataFormat.CSV -> TEXT_CSV_HEADER
DataFormat.CSV_WITHOUT_HEADERS -> TEXT_CSV_WITHOUT_HEADERS_HEADER
DataFormat.TSV -> TEXT_TSV_HEADER
DataFormat.JSON -> MediaType.APPLICATION_JSON_VALUE
else -> null
}

return super.getHeaders(name)
private fun overwriteWith(value: String): String {
log.debug { "Overwriting Accept header to $value due to format property" }
return value
}
}
Loading

0 comments on commit 24b9155

Please sign in to comment.