All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.http4k.contract.util.JsonSchema.kt Maven / Gradle / Ivy

There is a newer version: 5.31.0.0
Show newest version
package util

import org.http4k.format.Json
import org.http4k.format.JsonType
import org.http4k.lens.ParamMeta
import org.http4k.lens.ParamMeta.BooleanParam
import org.http4k.lens.ParamMeta.IntegerParam
import org.http4k.lens.ParamMeta.NumberParam
import org.http4k.lens.ParamMeta.StringParam

class IllegalSchemaException(message: String) : Exception(message)

data class JsonSchema(val node: NODE, val definitions: List>)

class JsonToJsonSchema(private val json: Json) {
    fun toSchema(node: NODE): JsonSchema = toSchema(JsonSchema(node, emptyList()))

    private fun toSchema(input: JsonSchema): JsonSchema =
        when (json.typeOf(input.node)) {
            JsonType.Object -> objectSchema(input)
            JsonType.Array -> arraySchema(input)
            JsonType.String -> JsonSchema(paramTypeSchema(StringParam), input.definitions)
            JsonType.Number -> numberSchema(input)
            JsonType.Boolean -> JsonSchema(paramTypeSchema(BooleanParam), input.definitions)
            JsonType.Null -> throw IllegalSchemaException("Cannot use a null value in a schema!")
            else -> throw IllegalSchemaException("unknown type")
        }

    private fun paramTypeSchema(paramMeta: ParamMeta): NODE = json.obj("type" to json.string(paramMeta.value))

    private fun numberSchema(input: JsonSchema): JsonSchema =
        JsonSchema(paramTypeSchema(if (json.text(input.node).contains(".")) NumberParam else IntegerParam), input.definitions)

    private fun arraySchema(input: JsonSchema): JsonSchema {
        val (node, definitions) = json.elements(input.node).toList().firstOrNull()?.let { toSchema(JsonSchema(it, input.definitions)) } ?: throw
        IllegalSchemaException("Cannot use an empty list to generate a schema!")
        return JsonSchema(json.obj("type" to json.string("array"), "items" to node), definitions)
    }

    private fun objectSchema(input: JsonSchema): JsonSchema {
        val (fields, subDefinitions) = json.fields(input.node).fold(listOf>() to input.definitions, {
            (memoFields, memoDefinitions), (first, second) ->
            val next = toSchema(JsonSchema(second, memoDefinitions))
            memoFields.plus(first to next.node) to next.definitions
        })

        val newDefinition = json.obj("type" to json.string("object"), "properties" to json.obj(fields))
        val definitionId = "object" + newDefinition.hashCode()
        val allDefinitions = subDefinitions.plus(definitionId to newDefinition)
        return JsonSchema(json.obj("\$ref" to json.string("#/definitions/$definitionId")), allDefinitions)
    }


}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy