Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 9 additions & 12 deletions codegen/src/main/kotlin/tools/samt/codegen/PublicApiMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class PublicApiMapper(
}

private class Params(
override val config: ConfigurationObject,
val controller: DiagnosticController
override val config: ConfigurationObject?,
val controller: DiagnosticController,
) : TransportConfigurationParserParams {

override fun reportError(message: String, context: ConfigurationElement?) {
Expand Down Expand Up @@ -129,16 +129,13 @@ class PublicApiMapper(
0 -> controller.reportGlobalWarning("No transport configuration parser found for transport '$name'")
1 -> {
val transportConfigurationParser = transportConfigurationParsers.single()
if (configuration != null) {
val transportConfigNode = TransportConfigurationMapper(provider, controller).parse(configuration!!)
val config = Params(transportConfigNode, controller)
try {
return transportConfigurationParser.parse(config)
} catch (e: Exception) {
controller.reportGlobalError("Failed to parse transport configuration for transport '$name': ${e.message}")
}
} else {
return transportConfigurationParser.default()
val transportConfigNode =
configuration?.let { TransportConfigurationMapper(provider, controller).parse(it) }
val config = Params(transportConfigNode, controller)
try {
return transportConfigurationParser.parse(config)
} catch (e: Exception) {
controller.reportGlobalError("Failed to parse transport configuration for transport '$name': ${e.message}")
}
}

Expand Down
112 changes: 59 additions & 53 deletions codegen/src/main/kotlin/tools/samt/codegen/http/HttpTransport.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package tools.samt.codegen.http

import tools.samt.api.plugin.TransportConfiguration
import tools.samt.api.plugin.TransportConfigurationParser
import tools.samt.api.plugin.TransportConfigurationParserParams
import tools.samt.api.plugin.asEnum
import tools.samt.api.transports.http.HttpMethod
import tools.samt.api.transports.http.SamtHttpTransport
import tools.samt.api.transports.http.SerializationMode
import tools.samt.api.transports.http.TransportMode

object HttpTransportConfigurationParser : TransportConfigurationParser {
override val transportName: String
get() = "http"

override fun default(): HttpTransportConfiguration = HttpTransportConfiguration(
serializationMode = HttpTransportConfiguration.SerializationMode.Json,
services = emptyList(),
)

private val isValidRegex = Regex("""\w+\s+\S+(\s+\{.*?\s+in\s+\S+})*""")
private val methodEndpointRegex = Regex("""(\w+)\s+(\S+)(.*)""")
private val parameterRegex = Regex("""\{(.*?)\s+in\s+(\S+)}""")

override fun parse(params: TransportConfigurationParserParams): HttpTransportConfiguration {
val config = params.config
val config = params.config ?: return HttpTransportConfiguration(
serializationMode = SerializationMode.Json,
services = emptyList(),
)
val serializationMode =
config.getFieldOrNull("serialization")?.asValue?.asEnum<HttpTransportConfiguration.SerializationMode>()
?: HttpTransportConfiguration.SerializationMode.Json
config.getFieldOrNull("serialization")?.asValue?.asEnum<SerializationMode>()
?: SerializationMode.Json

val services = config.getFieldOrNull("operations")?.asObject?.let { operations ->
val parsedServices = mutableListOf<HttpTransportConfiguration.ServiceConfiguration>()
Expand All @@ -36,14 +37,14 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {
val operationConfigurations = operationConfiguration.fields.filterKeys { it.asIdentifier != "basePath" }
val parsedOperations = mutableListOf<HttpTransportConfiguration.OperationConfiguration>()

operationConfigLoop@for ((key, value) in operationConfigurations) {
operationConfigLoop@ for ((key, value) in operationConfigurations) {
val operationConfig = value.asValue
val operation = key.asOperationName(service)
val operationName = operation.name

if (!(operationConfig.asString matches isValidRegex)) {
params.reportError(
"Invalid operation config for '$operationName', expected '<method> <path> <parameters>'. A valid example: 'POST /${operationName} {parameter1, parameter2 in query}'",
"Invalid operation config for '$operationName', expected '<method> <path> <parameters>'. A valid example: 'POST /${operationName} {parameter1, parameter2 in queryParam}'",
operationConfig
)
continue
Expand All @@ -61,11 +62,11 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {
val (method, path, parameterPart) = methodEndpointResult.destructured

val methodEnum = when (method) {
"GET" -> HttpTransportConfiguration.HttpMethod.Get
"POST" -> HttpTransportConfiguration.HttpMethod.Post
"PUT" -> HttpTransportConfiguration.HttpMethod.Put
"DELETE" -> HttpTransportConfiguration.HttpMethod.Delete
"PATCH" -> HttpTransportConfiguration.HttpMethod.Patch
"GET" -> HttpMethod.Get
"POST" -> HttpMethod.Post
"PUT" -> HttpMethod.Put
"DELETE" -> HttpMethod.Delete
"PATCH" -> HttpMethod.Patch
else -> {
params.reportError("Invalid http method '$method'", operationConfig)
continue
Expand Down Expand Up @@ -124,13 +125,16 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {
}

if (operation.parameters.none { it.name == pathParameterName }) {
params.reportError("Path parameter '$pathParameterName' not found in operation '$operationName'", operationConfig)
params.reportError(
"Path parameter '$pathParameterName' not found in operation '$operationName'",
operationConfig
)
continue
}

parameters += HttpTransportConfiguration.ParameterConfiguration(
name = pathParameterName,
transportMode = HttpTransportConfiguration.TransportMode.Path,
transportMode = TransportMode.Path,
)
}

Expand All @@ -139,10 +143,16 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {
for (parameterResult in parameterResults) {
val (names, type) = parameterResult.destructured
val transportMode = when (type) {
"query" -> HttpTransportConfiguration.TransportMode.Query
"header" -> HttpTransportConfiguration.TransportMode.Header
"body" -> HttpTransportConfiguration.TransportMode.Body
"cookie" -> HttpTransportConfiguration.TransportMode.Cookie
"query",
"queryParam",
"queryParams",
"queryParameter",
"queryParameters",
-> TransportMode.QueryParameter

"header", "headers" -> TransportMode.Header
"body" -> TransportMode.Body
"cookie", "cookies" -> TransportMode.Cookie
else -> {
params.reportError("Invalid transport mode '$type'", operationConfig)
continue
Expand All @@ -151,12 +161,18 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {

for (name in names.split(",").map { it.trim() }) {
if (operation.parameters.none { it.name == name }) {
params.reportError("Parameter '$name' not found in operation '$operationName'", operationConfig)
params.reportError(
"Parameter '$name' not found in operation '$operationName'",
operationConfig
)
continue
}

if (transportMode == HttpTransportConfiguration.TransportMode.Body && methodEnum == HttpTransportConfiguration.HttpMethod.Get) {
params.reportError("HTTP GET method doesn't accept '$name' as a BODY parameter", operationConfig)
if (transportMode == TransportMode.Body && methodEnum == HttpMethod.Get) {
params.reportError(
"HTTP GET method doesn't accept '$name' as a BODY parameter",
operationConfig
)
continue
}

Expand Down Expand Up @@ -193,13 +209,13 @@ object HttpTransportConfigurationParser : TransportConfigurationParser {
}

class HttpTransportConfiguration(
val serializationMode: SerializationMode,
override val serializationMode: SerializationMode,
val services: List<ServiceConfiguration>,
) : TransportConfiguration {
) : SamtHttpTransport {
class ServiceConfiguration(
val name: String,
val path: String,
val operations: List<OperationConfiguration>
val operations: List<OperationConfiguration>,
) {
fun getOperation(name: String): OperationConfiguration? {
return operations.firstOrNull { it.name == name }
Expand All @@ -222,48 +238,38 @@ class HttpTransportConfiguration(
val transportMode: TransportMode,
)

enum class SerializationMode {
Json,
}

enum class TransportMode {
Body, // encoded in request body via serializationMode
Query, // encoded as url query parameter
Path, // encoded as part of url path
Header, // encoded as HTTP header
Cookie, // encoded as HTTP cookie
}

enum class HttpMethod {
Get,
Post,
Put,
Delete,
Patch,
}

private fun getService(name: String): ServiceConfiguration? {
return services.firstOrNull { it.name == name }
}

fun getMethod(serviceName: String, operationName: String): HttpMethod {
override fun getMethod(serviceName: String, operationName: String): HttpMethod {
val service = getService(serviceName)
val operation = service?.getOperation(operationName)
return operation?.method ?: HttpMethod.Post
}

fun getPath(serviceName: String, operationName: String): String {
override fun getPath(serviceName: String, operationName: String): String {
val service = getService(serviceName)
val operation = service?.getOperation(operationName)
return operation?.path ?: "/$operationName"
}

fun getPath(serviceName: String): String {
override fun getFullPath(serviceName: String, operationName: String): String {
val service = getService(serviceName)
val operation = service?.getOperation(operationName)
return "${service?.path ?: ""}${operation?.path ?: "/$operationName"}"
}

override fun getServicePath(serviceName: String): String {
val service = getService(serviceName)
return service?.path ?: ""
}

fun getTransportMode(serviceName: String, operationName: String, parameterName: String): TransportMode {
override fun getTransportMode(
serviceName: String,
operationName: String,
parameterName: String,
): TransportMode {
val service = getService(serviceName)
val operation = service?.getOperation(operationName)
val parameter = operation?.getParameter(parameterName)
Expand All @@ -273,7 +279,7 @@ class HttpTransportConfiguration(
return mode

return if (operation?.method == HttpMethod.Get) {
TransportMode.Query
TransportMode.QueryParameter
} else {
TransportMode.Body
}
Expand Down
Loading