[{"data":1,"prerenderedAt":1832},["ShallowReactive",2],{"navigation_docs":3,"-guide-schema":93,"-guide-schema-surround":1827},[4,71],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":70},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,18,22,26,30,34,38,42,46,50,54,58,62,66],{"title":11,"path":12,"stem":13},"Getting started","\u002Fguide\u002Fgetting-started","1.guide\u002F01.getting-started",{"title":15,"path":16,"stem":17},"Adoption paths","\u002Fguide\u002Fadoption","1.guide\u002F02.adoption",{"title":19,"path":20,"stem":21},"Routes and typed $fetch","\u002Fguide\u002Froutes","1.guide\u002F02.routes",{"title":23,"path":24,"stem":25},"Kyo handlers","\u002Fguide\u002Fkyo","1.guide\u002F03.kyo",{"title":27,"path":28,"stem":29},"ZIO handlers","\u002Fguide\u002Fzio","1.guide\u002F04.zio",{"title":31,"path":32,"stem":33},"Configuration and secrets","\u002Fguide\u002Fconfiguration","1.guide\u002F05.configuration",{"title":35,"path":36,"stem":37},"Application and request lifetimes","\u002Fguide\u002Flifetimes","1.guide\u002F06.lifetimes",{"title":39,"path":40,"stem":41},"Schemas","\u002Fguide\u002Fschema","1.guide\u002F07.schema",{"title":43,"path":44,"stem":45},"PostgreSQL","\u002Fguide\u002Fdatabase","1.guide\u002F08.database",{"title":47,"path":48,"stem":49},"Streaming and cancellation","\u002Fguide\u002Fstreaming","1.guide\u002F09.streaming",{"title":51,"path":52,"stem":53},"Testing","\u002Fguide\u002Ftesting","1.guide\u002F10.testing",{"title":55,"path":56,"stem":57},"Nitro storage and NuxtHub KV","\u002Fguide\u002Fstorage","1.guide\u002F11.storage",{"title":59,"path":60,"stem":61},"Debug Scala handlers","\u002Fguide\u002Fdebugging","1.guide\u002F12.debugging",{"title":63,"path":64,"stem":65},"npm build tooling","\u002Fguide\u002Fnpm-tooling","1.guide\u002F13.npm-tooling",{"title":67,"path":68,"stem":69},"Set up h34s with a coding assistant","\u002Fguide\u002Fagent-setup","1.guide\u002F14.agent-setup",false,{"title":72,"icon":73,"path":74,"stem":75,"children":76,"page":70},"Reference","i-lucide-library","\u002Freference","2.reference",[77,81,85,89],{"title":78,"path":79,"stem":80},"Architecture","\u002Freference\u002Farchitecture","2.reference\u002F1.architecture",{"title":82,"path":83,"stem":84},"Releases","\u002Freference\u002Freleases","2.reference\u002F2.releases",{"title":86,"path":87,"stem":88},"Compatibility","\u002Freference\u002Fcompatibility","2.reference\u002F3.compatibility",{"title":90,"path":91,"stem":92},"Migration guide","\u002Freference\u002Fmigration","2.reference\u002F4.migration",{"id":94,"title":39,"body":95,"description":1821,"extension":1822,"links":1823,"meta":1824,"navigation":429,"path":40,"seo":1825,"stem":41,"__hash__":1826},"docs\u002F1.guide\u002F07.schema.md",{"type":96,"value":97,"toc":1808},"minimark",[98,111,114,171,174,194,199,340,362,365,369,379,582,585,637,647,650,732,737,744,894,901,905,950,954,968,1250,1259,1280,1287,1373,1380,1400,1403,1419,1442,1529,1556,1560,1590,1594,1660,1671,1675,1690,1694,1741,1748,1751,1804],[99,100,101,102,106,107,110],"p",{},"Schemas are optional. ",[103,104,105],"code",{},"NativeConverter"," is the type class every h34s API asks for, and a plain ",[103,108,109],{},"derives NativeConverter"," is a complete path. Add a schema when you want validation in the model, or JSON and YAML from the same definition.",[99,112,113],{},"With a schema, define each model once:",[115,116,121],"pre",{"className":117,"code":118,"language":119,"meta":120,"style":120},"language-scala shiki shiki-themes github-light github-light github-dark","final case class Greeting(message: String) derives Schema, NativeSchema\n","scala","",[103,122,123],{"__ignoreMap":120},[124,125,128,132,135,138,142,146,150,153,156,159,162,165,168],"span",{"class":126,"line":127},"line",1,[124,129,131],{"class":130},"s8jYJ","final",[124,133,134],{"class":130}," case",[124,136,137],{"class":130}," class",[124,139,141],{"class":140},"snPdu"," Greeting",[124,143,145],{"class":144},"sxrX7","(",[124,147,149],{"class":148},"sP4rz","message",[124,151,152],{"class":144},": ",[124,154,155],{"class":140},"String",[124,157,158],{"class":144},") ",[124,160,161],{"class":130},"derives",[124,163,164],{"class":140}," Schema",[124,166,167],{"class":144},", ",[124,169,170],{"class":140},"NativeSchema\n",[99,172,173],{},"That one derivation gives the native value h34s sends and reads, JSON text, YAML text (Kyo only), and validation that runs on every request body read.",[99,175,176,180,181,184,185,188,189,193],{},[177,178,179],"strong",{},"Status."," This page describes both bridges in ",[103,182,183],{},"0.2.0-alpha.1",". The older ",[103,186,187],{},"0.1.0-alpha.1"," had a different ZIO schema reader; see the ",[190,191,192],"a",{"href":91},"migration guide",".",[195,196,198],"h2",{"id":197},"choose-a-bridge","Choose a bridge",[200,201,202,217],"table",{},[203,204,205],"thead",{},[206,207,208,211,214],"tr",{},[209,210],"th",{},[209,212,213],{},"Kyo",[209,215,216],{},"ZIO",[218,219,220,236,251,270,290,307,329],"tbody",{},[206,221,222,226,231],{},[223,224,225],"td",{},"Module",[223,227,228],{},[103,229,230],{},"native-converter-kyo-schema-ext",[223,232,233],{},[103,234,235],{},"native-converter-zio-schema-ext",[206,237,238,241,246],{},[223,239,240],{},"Package",[223,242,243],{},[103,244,245],{},"dev.yuri4n.exts.ntcvkyoschema",[223,247,248],{},[103,249,250],{},"dev.yuri4n.exts.ntcvzioschema",[206,252,253,256,261],{},[223,254,255],{},"Derive",[223,257,258],{},[103,259,260],{},"derives Schema, NativeSchema",[223,262,263,265,266,269],{},[103,264,260],{}," (needs ",[103,267,268],{},"import zio.schema.derived",")",[206,271,272,275,284],{},[223,273,274],{},"JSON",[223,276,277,278,167,281],{},"kyo-schema-json: ",[103,279,280],{},"Json.encode",[103,282,283],{},"Json.decode",[223,285,286,287],{},"zio-schema-json: ",[103,288,289],{},"JsonCodec",[206,291,292,295,304],{},[223,293,294],{},"YAML",[223,296,297,298,167,301],{},"kyo-schema-yaml: ",[103,299,300],{},"encodeString[Yaml]",[103,302,303],{},"decodeString[Yaml]",[223,305,306],{},"Not on Scala.js: zio-json-yaml is published for the JVM only",[206,308,309,312,318],{},[223,310,311],{},"Validation",[223,313,314,317],{},[103,315,316],{},"Schema[A].check(...)"," and friends",[223,319,320,322,323,167,326,269],{},[103,321,311],{}," in the schema (",[103,324,325],{},".validation",[103,327,328],{},"@validate",[206,330,331,334,337],{},[223,332,333],{},"Messages",[223,335,336],{},"Your check messages",[223,338,339],{},"Built from the rule and its bounds",[99,341,342,343,346,347,350,351,354,355,358,359,361],{},"The bridges depend on the native layer (",[103,344,345],{},"h3-ext",") and their schema library only. Neither installs a blanket instance: a type gets a ",[103,348,349],{},"NativeSchema"," only when it derives one or calls ",[103,352,353],{},"NativeSchema[A]"," (Kyo) or ",[103,356,357],{},"NativeSchema.derived"," (ZIO). A type can keep a separately derived ",[103,360,105],{},"; the two do not conflict.",[99,363,364],{},"Add kyo-schema-json and kyo-schema-yaml (Kyo 1.0.0-RC7) to your application yourself when you need JSON or YAML text. The bridge does not depend on them.",[195,366,368],{"id":367},"kyo-derive-validate-use","Kyo: derive, validate, use",[99,370,371,372,374,375,378],{},"Derive both at once for a model without checks. For a model with checks, declare the schema in the companion and derive only ",[103,373,349],{},"; kyo-schema has no check annotations, so this keeps one schema. This is the demo's ",[103,376,377],{},"Greetings.scala",":",[115,380,382],{"className":117,"code":381,"language":119,"meta":120,"style":120},"import dev.yuri4n.exts.ntcvkyoschema.NativeSchema\nimport kyo.*\n\n\u002F** The request model. Its one schema carries the validation; `NativeSchema` derives from it, so\n  * `request.body.json[GreetingRequest]` answers 422 with these messages and the `name` path.\n  *\u002F\nfinal case class GreetingRequest(name: String) derives NativeSchema\n\nobject GreetingRequest:\n    given Schema[GreetingRequest] = Schema[GreetingRequest]\n      .check(_.name)(_.trim.nonEmpty, \"must not be blank\")\n      .checkMaxLength(_.name)(80)\n\nfinal case class Greeting(message: String) derives Schema, NativeSchema\n",[103,383,384,411,424,431,438,444,450,478,483,494,523,536,548,553],{"__ignoreMap":120},[124,385,386,389,392,394,397,399,402,404,407,409],{"class":126,"line":127},[124,387,388],{"class":130},"import",[124,390,391],{"class":140}," dev",[124,393,193],{"class":144},[124,395,396],{"class":140},"yuri4n",[124,398,193],{"class":144},[124,400,401],{"class":140},"exts",[124,403,193],{"class":144},[124,405,406],{"class":140},"ntcvkyoschema",[124,408,193],{"class":144},[124,410,170],{"class":140},[124,412,414,416,419,421],{"class":126,"line":413},2,[124,415,388],{"class":130},[124,417,418],{"class":140}," kyo",[124,420,193],{"class":144},[124,422,423],{"class":140},"*\n",[124,425,427],{"class":126,"line":426},3,[124,428,430],{"emptyLinePlaceholder":429},true,"\n",[124,432,434],{"class":126,"line":433},4,[124,435,437],{"class":436},"sCsY4","\u002F** The request model. Its one schema carries the validation; `NativeSchema` derives from it, so\n",[124,439,441],{"class":126,"line":440},5,[124,442,443],{"class":436},"  * `request.body.json[GreetingRequest]` answers 422 with these messages and the `name` path.\n",[124,445,447],{"class":126,"line":446},6,[124,448,449],{"class":436},"  *\u002F\n",[124,451,453,455,457,459,462,464,467,469,471,473,475],{"class":126,"line":452},7,[124,454,131],{"class":130},[124,456,134],{"class":130},[124,458,137],{"class":130},[124,460,461],{"class":140}," GreetingRequest",[124,463,145],{"class":144},[124,465,466],{"class":148},"name",[124,468,152],{"class":144},[124,470,155],{"class":140},[124,472,158],{"class":144},[124,474,161],{"class":130},[124,476,477],{"class":140}," NativeSchema\n",[124,479,481],{"class":126,"line":480},8,[124,482,430],{"emptyLinePlaceholder":429},[124,484,486,489,491],{"class":126,"line":485},9,[124,487,488],{"class":130},"object",[124,490,461],{"class":140},[124,492,493],{"class":130},":\n",[124,495,497,500,502,505,508,511,514,516,518,520],{"class":126,"line":496},10,[124,498,499],{"class":130},"    given",[124,501,164],{"class":140},[124,503,504],{"class":144},"[",[124,506,507],{"class":140},"GreetingRequest",[124,509,510],{"class":144},"] ",[124,512,513],{"class":130},"=",[124,515,164],{"class":140},[124,517,504],{"class":144},[124,519,507],{"class":140},[124,521,522],{"class":144},"]\n",[124,524,526,529,533],{"class":126,"line":525},11,[124,527,528],{"class":144},"      .check(_.name)(_.trim.nonEmpty, ",[124,530,532],{"class":531},"sIIMD","\"must not be blank\"",[124,534,535],{"class":144},")\n",[124,537,539,542,546],{"class":126,"line":538},12,[124,540,541],{"class":144},"      .checkMaxLength(_.name)(",[124,543,545],{"class":544},"sBjJW","80",[124,547,535],{"class":144},[124,549,551],{"class":126,"line":550},13,[124,552,430],{"emptyLinePlaceholder":429},[124,554,556,558,560,562,564,566,568,570,572,574,576,578,580],{"class":126,"line":555},14,[124,557,131],{"class":130},[124,559,134],{"class":130},[124,561,137],{"class":130},[124,563,141],{"class":140},[124,565,145],{"class":144},[124,567,149],{"class":148},[124,569,152],{"class":144},[124,571,155],{"class":140},[124,573,158],{"class":144},[124,575,161],{"class":130},[124,577,164],{"class":140},[124,579,167],{"class":144},[124,581,170],{"class":140},[99,583,584],{},"The handler asks for the validated model and repeats no checks:",[115,586,588],{"className":117,"code":587,"language":119,"meta":120,"style":120},"for\n  input    \u003C- request.body.json[GreetingRequest]\n  greeting \u003C- Env.use[Greetings](_.greet(input.name))\nyield greeting\n",[103,589,590,595,610,629],{"__ignoreMap":120},[124,591,592],{"class":126,"line":127},[124,593,594],{"class":130},"for\n",[124,596,597,600,603,606,608],{"class":126,"line":413},[124,598,599],{"class":144},"  input    ",[124,601,602],{"class":130},"\u003C-",[124,604,605],{"class":144}," request.body.json[",[124,607,507],{"class":140},[124,609,522],{"class":144},[124,611,612,615,617,620,623,626],{"class":126,"line":426},[124,613,614],{"class":144},"  greeting ",[124,616,602],{"class":130},[124,618,619],{"class":140}," Env",[124,621,622],{"class":144},".use[",[124,624,625],{"class":140},"Greetings",[124,627,628],{"class":144},"](_.greet(input.name))\n",[124,630,631,634],{"class":126,"line":433},[124,632,633],{"class":130},"yield",[124,635,636],{"class":144}," greeting\n",[99,638,639,640,643,644,193],{},"A blank name gets a 422 with ",[103,641,642],{},"{\"errors\":[{\"message\":\"must not be blank\",\"path\":\"name\"}]}",". An 81-character name gets ",[103,645,646],{},"{\"errors\":[{\"message\":\"length must be \u003C= 80\",\"path\":\"name\"}]}",[99,648,649],{},"The same schema gives JSON and YAML text:",[115,651,653],{"className":117,"code":652,"language":119,"meta":120,"style":120},"val json: String = Json.encode(greeting)\nval back = Json.decode[Greeting](json)                         \u002F\u002F a Result\nval yaml: String = summon[Schema[Greeting]].encodeString[Yaml](greeting)\n",[103,654,655,677,700],{"__ignoreMap":120},[124,656,657,660,663,665,668,671,674],{"class":126,"line":127},[124,658,659],{"class":130},"val",[124,661,662],{"class":148}," json",[124,664,378],{"class":130},[124,666,667],{"class":140}," String",[124,669,670],{"class":130}," =",[124,672,673],{"class":140}," Json",[124,675,676],{"class":144},".encode(greeting)\n",[124,678,679,681,684,686,688,691,694,697],{"class":126,"line":413},[124,680,659],{"class":130},[124,682,683],{"class":148}," back",[124,685,670],{"class":130},[124,687,673],{"class":140},[124,689,690],{"class":144},".decode[",[124,692,693],{"class":140},"Greeting",[124,695,696],{"class":144},"](json)                         ",[124,698,699],{"class":436},"\u002F\u002F a Result\n",[124,701,702,704,707,709,711,713,716,719,721,723,726,729],{"class":126,"line":426},[124,703,659],{"class":130},[124,705,706],{"class":148}," yaml",[124,708,378],{"class":130},[124,710,667],{"class":140},[124,712,670],{"class":130},[124,714,715],{"class":144}," summon[",[124,717,718],{"class":140},"Schema",[124,720,504],{"class":144},[124,722,693],{"class":140},[124,724,725],{"class":144},"]].encodeString[",[124,727,728],{"class":140},"Yaml",[124,730,731],{"class":144},"](greeting)\n",[733,734,736],"h3",{"id":735},"kyo-wire-shapes","Kyo wire shapes",[99,738,739,740,743],{},"The native value is what ",[103,741,742],{},"JSON.parse(Json.encode(x))"," would give, built without JSON text:",[200,745,746,756],{},[203,747,748],{},[206,749,750,753],{},[209,751,752],{},"Scala",[209,754,755],{},"Native value",[218,757,758,778,800,810,824,840,853,864,884],{},[206,759,760,765],{},[223,761,762],{},[103,763,764],{},"None",[223,766,767,768,771,772,775,776],{},"The key is absent. On input, absent, ",[103,769,770],{},"null"," and ",[103,773,774],{},"undefined"," all decode to ",[103,777,764],{},[206,779,780,783],{},[223,781,782],{},"Enum case, sealed trait case",[223,784,785,786,167,789,792,793,796,797],{},"A single-key object: ",[103,787,788],{},"{\"Red\":{}}",[103,790,791],{},"{\"Circle\":{\"radius\":1.5}}",". ",[103,794,795],{},"@discriminator(\"type\")"," gives ",[103,798,799],{},"{\"type\":\"Joined\",...}",[206,801,802,807],{},[223,803,804],{},[103,805,806],{},"Map[String, A]",[223,808,809],{},"An object",[206,811,812,818],{},[223,813,814,817],{},[103,815,816],{},"Map[Int, A]"," and other keys",[223,819,820,821],{},"An array of ",[103,822,823],{},"{\"key\":...,\"value\":...}",[206,825,826,834],{},[223,827,828,167,831],{},[103,829,830],{},"BigDecimal",[103,832,833],{},"BigInt",[223,835,836,837,839],{},"Strings. Decoding rejects (generic 422) a string longer than 1000 characters and a ",[103,838,830],{}," exponent beyond +\u002F-10000, before parsing: Scala.js parses big numbers in quadratic time",[206,841,842,850],{},[223,843,844,167,847],{},[103,845,846],{},"Instant",[103,848,849],{},"Duration",[223,851,852],{},"ISO strings",[206,854,855,861],{},[223,856,857,858,269],{},"Bytes (",[103,859,860],{},"Span[Byte]",[223,862,863],{},"A base64 string",[206,865,866,872],{},[223,867,868,871],{},[103,869,870],{},"Double"," NaN and infinities",[223,873,874,875,167,878,167,881],{},"The strings ",[103,876,877],{},"\"NaN\"",[103,879,880],{},"\"Infinity\"",[103,882,883],{},"\"-Infinity\"",[206,885,886,891],{},[223,887,888],{},[103,889,890],{},"Long",[223,892,893],{},"A number; decoding accepts only safe integers (up to 2^53 - 1)",[99,895,896,897,193],{},"You do not write TypeScript types for these shapes: h34s generates them. See ",[190,898,900],{"href":899},"#typescript-types","TypeScript types",[733,902,904],{"id":903},"kyo-validation-rules","Kyo validation rules",[906,907,908,920,927,933,936],"ul",{},[909,910,911,912,915,916,919],"li",{},"Only the root schema's checks run, like ",[103,913,914],{},"Schema.validate",". Put checks on the root with focus paths, such as ",[103,917,918],{},"_.customer.name",". A nested type's own checks do not run.",[909,921,922,923,926],{},"Each failed check is one entry: your message, and the field path when the check is on a field (",[103,924,925],{},"customer.name","). A check on the whole value has no path.",[909,928,929,930,193],{},"A value with the wrong shape (missing field, wrong type, out-of-range integer, a non-plain object, invalid ISO or base64 text) is one generic entry: ",[103,931,932],{},"Request body does not match the expected shape",[909,934,935],{},"An exception from a schema transform is a defect (opaque 500), never blamed on the input.",[909,937,938,939,167,942,945,946,949],{},"A fluent ",[103,940,941],{},"Schema.rename",[103,943,944],{},"renameAllFields"," or ",[103,947,948],{},".discriminator",", and adjacent, tuple or untagged unions, are converted generically; strict number checks then do not apply to those values.",[195,951,953],{"id":952},"zio-derive-validate-use","ZIO: derive, validate, use",[99,955,956,957,960,961,964,965,378],{},"Import ",[103,958,959],{},"zio.schema.derived"," for ",[103,962,963],{},"derives Schema",". Put normalization and validation in the schema. This is the demo's ",[103,966,967],{},"Notes.scala",[115,969,971],{"className":117,"code":970,"language":119,"meta":120,"style":120},"import dev.yuri4n.exts.ntcvzioschema.NativeSchema\nimport zio.schema.{DeriveSchema, Schema, StandardType, derived}\nimport zio.schema.validation.Validation\n\n\u002F** The JSON that the Notes routes send. One derivation: the ZIO Schema and the native converter. *\u002F\nfinal case class NoteView(id: Int, text: String) derives Schema, NativeSchema\n\n\u002F** The JSON that `POST \u002Fapi\u002Fnotes` reads. *\u002F\nfinal case class CreateNote(text: String) derives NativeSchema\n\nobject CreateNote:\n    \u002F** Trims the text, then requires 1-2000 characters. The native converter uses this schema. *\u002F\n    given Schema[CreateNote] =\n      given Schema[String] = Schema.Primitive(StandardType.StringType)\n        .transform(_.trim, identity)\n        .validation(Validation.minLength(1) && Validation.maxLength(2000))\n      DeriveSchema.gen[CreateNote]\n",[103,972,973,996,1031,1051,1055,1060,1100,1104,1109,1134,1138,1146,1151,1167,1200,1206,1237],{"__ignoreMap":120},[124,974,975,977,979,981,983,985,987,989,992,994],{"class":126,"line":127},[124,976,388],{"class":130},[124,978,391],{"class":140},[124,980,193],{"class":144},[124,982,396],{"class":140},[124,984,193],{"class":144},[124,986,401],{"class":140},[124,988,193],{"class":144},[124,990,991],{"class":140},"ntcvzioschema",[124,993,193],{"class":144},[124,995,170],{"class":140},[124,997,998,1000,1003,1005,1008,1011,1014,1016,1018,1020,1023,1025,1028],{"class":126,"line":413},[124,999,388],{"class":130},[124,1001,1002],{"class":140}," zio",[124,1004,193],{"class":144},[124,1006,1007],{"class":140},"schema",[124,1009,1010],{"class":144},".{",[124,1012,1013],{"class":140},"DeriveSchema",[124,1015,167],{"class":144},[124,1017,718],{"class":140},[124,1019,167],{"class":144},[124,1021,1022],{"class":140},"StandardType",[124,1024,167],{"class":144},[124,1026,1027],{"class":140},"derived",[124,1029,1030],{"class":144},"}\n",[124,1032,1033,1035,1037,1039,1041,1043,1046,1048],{"class":126,"line":426},[124,1034,388],{"class":130},[124,1036,1002],{"class":140},[124,1038,193],{"class":144},[124,1040,1007],{"class":140},[124,1042,193],{"class":144},[124,1044,1045],{"class":140},"validation",[124,1047,193],{"class":144},[124,1049,1050],{"class":140},"Validation\n",[124,1052,1053],{"class":126,"line":433},[124,1054,430],{"emptyLinePlaceholder":429},[124,1056,1057],{"class":126,"line":440},[124,1058,1059],{"class":436},"\u002F** The JSON that the Notes routes send. One derivation: the ZIO Schema and the native converter. *\u002F\n",[124,1061,1062,1064,1066,1068,1071,1073,1076,1078,1081,1083,1086,1088,1090,1092,1094,1096,1098],{"class":126,"line":446},[124,1063,131],{"class":130},[124,1065,134],{"class":130},[124,1067,137],{"class":130},[124,1069,1070],{"class":140}," NoteView",[124,1072,145],{"class":144},[124,1074,1075],{"class":148},"id",[124,1077,152],{"class":144},[124,1079,1080],{"class":140},"Int",[124,1082,167],{"class":144},[124,1084,1085],{"class":148},"text",[124,1087,152],{"class":144},[124,1089,155],{"class":140},[124,1091,158],{"class":144},[124,1093,161],{"class":130},[124,1095,164],{"class":140},[124,1097,167],{"class":144},[124,1099,170],{"class":140},[124,1101,1102],{"class":126,"line":452},[124,1103,430],{"emptyLinePlaceholder":429},[124,1105,1106],{"class":126,"line":480},[124,1107,1108],{"class":436},"\u002F** The JSON that `POST \u002Fapi\u002Fnotes` reads. *\u002F\n",[124,1110,1111,1113,1115,1117,1120,1122,1124,1126,1128,1130,1132],{"class":126,"line":485},[124,1112,131],{"class":130},[124,1114,134],{"class":130},[124,1116,137],{"class":130},[124,1118,1119],{"class":140}," CreateNote",[124,1121,145],{"class":144},[124,1123,1085],{"class":148},[124,1125,152],{"class":144},[124,1127,155],{"class":140},[124,1129,158],{"class":144},[124,1131,161],{"class":130},[124,1133,477],{"class":140},[124,1135,1136],{"class":126,"line":496},[124,1137,430],{"emptyLinePlaceholder":429},[124,1139,1140,1142,1144],{"class":126,"line":525},[124,1141,488],{"class":130},[124,1143,1119],{"class":140},[124,1145,493],{"class":130},[124,1147,1148],{"class":126,"line":538},[124,1149,1150],{"class":436},"    \u002F** Trims the text, then requires 1-2000 characters. The native converter uses this schema. *\u002F\n",[124,1152,1153,1155,1157,1159,1162,1164],{"class":126,"line":550},[124,1154,499],{"class":130},[124,1156,164],{"class":140},[124,1158,504],{"class":144},[124,1160,1161],{"class":140},"CreateNote",[124,1163,510],{"class":144},[124,1165,1166],{"class":130},"=\n",[124,1168,1169,1172,1174,1176,1178,1180,1182,1184,1186,1189,1191,1193,1195,1198],{"class":126,"line":555},[124,1170,1171],{"class":130},"      given",[124,1173,164],{"class":140},[124,1175,504],{"class":144},[124,1177,155],{"class":140},[124,1179,510],{"class":144},[124,1181,513],{"class":130},[124,1183,164],{"class":140},[124,1185,193],{"class":144},[124,1187,1188],{"class":140},"Primitive",[124,1190,145],{"class":144},[124,1192,1022],{"class":140},[124,1194,193],{"class":144},[124,1196,1197],{"class":140},"StringType",[124,1199,535],{"class":144},[124,1201,1203],{"class":126,"line":1202},15,[124,1204,1205],{"class":144},"        .transform(_.trim, identity)\n",[124,1207,1209,1212,1214,1217,1220,1222,1225,1228,1231,1234],{"class":126,"line":1208},16,[124,1210,1211],{"class":144},"        .validation(",[124,1213,311],{"class":140},[124,1215,1216],{"class":144},".minLength(",[124,1218,1219],{"class":544},"1",[124,1221,158],{"class":144},[124,1223,1224],{"class":130},"&&",[124,1226,1227],{"class":140}," Validation",[124,1229,1230],{"class":144},".maxLength(",[124,1232,1233],{"class":544},"2000",[124,1235,1236],{"class":144},"))\n",[124,1238,1240,1243,1246,1248],{"class":126,"line":1239},17,[124,1241,1242],{"class":140},"      DeriveSchema",[124,1244,1245],{"class":144},".gen[",[124,1247,1161],{"class":140},[124,1249,522],{"class":144},[99,1251,1252,1255,1256,193],{},[103,1253,1254],{},"request.body.json[CreateNote]"," trims the text and checks its length. A blank text gets a 422 with ",[103,1257,1258],{},"{\"errors\":[{\"message\":\"must have at least 1 character\",\"path\":\"text\"}]}",[99,1260,1261,1262,945,1265,1268,1269,771,1272,1275,1276,1279],{},"ZIO Schema's own validation messages quote the input, so the bridge builds messages from the rule and its bounds instead, such as ",[103,1263,1264],{},"must have at least 3 characters",[103,1266,1267],{},"must be greater than 17",". Paths look like ",[103,1270,1271],{},"lead.name",[103,1273,1274],{},"members[1].name",". A negated rule (",[103,1277,1278],{},"!",") is reported with the wording of the rule it negates; this is a zio-schema limitation.",[99,1281,1282,1283,1286],{},"The ZIO bridge supports these shapes and fails with ",[103,1284,1285],{},"UnsupportedSchema"," when the converter is created for any other:",[200,1288,1289,1298],{},[203,1290,1291],{},[206,1292,1293,1296],{},[209,1294,1295],{},"Schema form",[209,1297,755],{},[218,1299,1300,1312,1321,1330,1342,1357,1365],{},[206,1301,1302,1309],{},[223,1303,1304,167,1306],{},[103,1305,155],{},[103,1307,1308],{},"Boolean",[223,1310,1311],{},"Strict primitives",[206,1313,1314,1318],{},[223,1315,1316],{},[103,1317,1080],{},[223,1319,1320],{},"An integer in the 32-bit range",[206,1322,1323,1327],{},[223,1324,1325],{},[103,1326,870],{},[223,1328,1329],{},"A finite number",[206,1331,1332,1335],{},[223,1333,1334],{},"Records (case classes)",[223,1336,1337,1338,1341],{},"Plain objects; field names, aliases, defaults, transient fields and ",[103,1339,1340],{},"rejectExtraFields"," are respected",[206,1343,1344,1349],{},[223,1345,1346],{},[103,1347,1348],{},"Option",[223,1350,1351,1352,1354,1355],{},"Absent or ",[103,1353,770],{}," is ",[103,1356,764],{},[206,1358,1359,1362],{},[223,1360,1361],{},"Sequences",[223,1363,1364],{},"Arrays",[206,1366,1367,1370],{},[223,1368,1369],{},"Lazy and transformed schemas",[223,1371,1372],{},"Through their underlying schema",[99,1374,1375,1376,1379],{},"Enums, sealed traits, maps, sets, tuples, ",[103,1377,1378],{},"Either"," and other primitives are not supported by the ZIO bridge yet.",[99,1381,1382,1385,1386,1389,1390,167,1393,771,1396,1399],{},[103,1383,1384],{},"NativeSchema(schema)"," also returns an explicit ",[103,1387,1388],{},"Codec"," with ",[103,1391,1392],{},"decode",[103,1394,1395],{},"validate",[103,1397,1398],{},"encode"," for code that holds a native value. Ordinary handlers do not need it.",[195,1401,900],{"id":1402},"typescript-types",[99,1404,1405,1406,1409,1410,1413,1414,193],{},"Both bridges' converters describe the TypeScript type of what they write (",[103,1407,1408],{},"WireType.Described","). A route that returns such a type gets that type in its generated declaration, so ",[103,1411,1412],{},"$fetch"," is typed without hand-written interfaces. See ",[190,1415,1416,1417],{"href":20},"routes and typed ",[103,1418,1412],{},[99,1420,1421,1422,1425,1426,1429,1430,1433,1434,1437,1438,792],{},"Each record (and, in Kyo, each sealed trait and enum) is a named model: ",[103,1423,1424],{},"h34s-scala"," declares it once as ",[103,1427,1428],{},"export type Note = ...",", and your app imports it with ",[103,1431,1432],{},"import type { Note } from '#h34s\u002Fmodels'",". A generic instantiation such as ",[103,1435,1436],{},"Page[Note]"," is written out where it is used. See ",[190,1439,1441],{"href":1440},"\u002Fguide\u002Froutes#use-the-models-in-your-app","use the models in your app",[200,1443,1444,1454],{},[203,1445,1446],{},[206,1447,1448,1451],{},[209,1449,1450],{},"Bridge",[209,1452,1453],{},"TypeScript type",[218,1455,1456,1495],{},[206,1457,1458,1460],{},[223,1459,213],{},[223,1461,1462,1463,1466,1467,1470,1471,1473,1474,1477,1478,1481,1482,1485,1486,771,1488,1473,1491,1494],{},"The shapes in the table above: records with their wire names (",[103,1464,1465],{},"@rename","), optional fields as ",[103,1468,1469],{},"name?: T | null",", collections as arrays, ",[103,1472,806],{}," as ",[103,1475,1476],{},"Record\u003Cstring, T>",", other maps as ",[103,1479,1480],{},"{ key; value }"," arrays, sealed traits and enums as one-key objects or ",[103,1483,1484],{},"@discriminator"," objects, ",[103,1487,870],{},[103,1489,1490],{},"Float",[103,1492,1493],{},"number | \"NaN\" | \"Infinity\" | \"-Infinity\"",", big numbers, instants, durations and bytes as strings",[206,1496,1497,1499],{},[223,1498,216],{},[223,1500,1501,1502,1505,1506,1509,1510,1473,1512,1515,1516,167,1518,167,1520,167,1522,1524,1525,1528],{},"Records with their wire names (",[103,1503,1504],{},"@fieldName",") and without ",[103,1507,1508],{},"@transientField"," fields, ",[103,1511,1348],{},[103,1513,1514],{},"T | null",", sequences as arrays, ",[103,1517,155],{},[103,1519,1308],{},[103,1521,1080],{},[103,1523,870],{},"; a transform has its underlying type; a recursive record refers to its model by name where it repeats (",[103,1526,1527],{},"unknown"," when the type is written out)",[99,1530,1531,1532,1535,1536,167,1538,167,1541,1544,1545,1547,1548,1550,1551,167,1553,1555],{},"The ZIO type follows the bridge's encoder case by case. The Kyo type follows the schema's ",[103,1533,1534],{},"Structure",", which does not show fluent changes such as ",[103,1537,941],{},[103,1539,1540],{},"drop",[103,1542,1543],{},"add"," or omit policies, also in the schema of a nested type. So the Kyo bridge checks its type against its encoder: it reads and writes sample values of every shape (each union member, present and absent options, filled and empty collections) and gives ",[103,1546,1527],{}," when an output does not match. A Kyo type with fluent changes is therefore ",[103,1549,1527],{},"; prefer annotations (",[103,1552,1465],{},[103,1554,1484],{},") for types you send to TypeScript clients.",[195,1557,1559],{"id":1558},"secrets-in-a-schema-type","Secrets in a schema type",[99,1561,1562,1565,1566,1568,1569,1572,1573,354,1576,1579,1580,1582,1583,1586,1587,193],{},[103,1563,1564],{},"Secret"," has a ",[103,1567,105],{},", but no schema library knows it. Each bridge provides a ",[103,1570,1571],{},"Schema[Secret]"," that is a string on the wire: import ",[103,1574,1575],{},"dev.yuri4n.exts.ntcvkyoschema.secretSchema",[103,1577,1578],{},"dev.yuri4n.exts.ntcvzioschema.secretSchema"," (ZIO) where you derive a schema that holds a ",[103,1581,1564],{},", such as a config model. A wrong value type is the generic 422 (or a ",[103,1584,1585],{},"ConfigError"," for runtime config), without the value. JSON or YAML that you write with this schema contains the plain value, so do not encode a secret into a response or a log. See ",[190,1588,1589],{"href":32},"configuration",[195,1591,1593],{"id":1592},"request-errors","Request errors",[200,1595,1596,1609],{},[203,1597,1598],{},[206,1599,1600,1603,1606],{},[209,1601,1602],{},"Problem",[209,1604,1605],{},"Status",[209,1607,1608],{},"Entries",[218,1610,1611,1624,1635,1649],{},[206,1612,1613,1616,1619],{},[223,1614,1615],{},"Body is not valid JSON",[223,1617,1618],{},"400",[223,1620,1621],{},[103,1622,1623],{},"Request body is not valid JSON",[206,1625,1626,1629,1632],{},[223,1627,1628],{},"Wrong shape",[223,1630,1631],{},"422",[223,1633,1634],{},"One generic entry, no input values",[206,1636,1637,1640,1642],{},[223,1638,1639],{},"Failed checks",[223,1641,1631],{},[223,1643,1644,1645,1648],{},"One entry per check, with ",[103,1646,1647],{},"path"," when known",[206,1650,1651,1654,1657],{},[223,1652,1653],{},"Exception in a transform, validator or converter",[223,1655,1656],{},"500",[223,1658,1659],{},"Opaque; diagnostics only in development or debug mode",[99,1661,1662,1663,1666,1667,1670],{},"Do not catch every ",[103,1664,1665],{},"Throwable"," and turn it into a ",[103,1668,1669],{},"SafeError",". That would show programming errors to clients as if they were input problems.",[195,1672,1674],{"id":1673},"keep-a-nativeconverter-only-path","Keep a NativeConverter-only path",[99,1676,1677,1678,1680,1681,1683,1684,1686,1687,1689],{},"You never need a schema. ",[103,1679,109],{}," works with every h34s API: body reads, responses, configuration, storage and streams. Shape errors are still a generic 422. A derived ",[103,1682,105],{}," does not validate domain rules, and version 0.9 accepts a missing or ",[103,1685,770],{}," value for a ",[103,1688,155],{}," field; check such rules in your code.",[195,1691,1693],{"id":1692},"dependencies-and-compatibility","Dependencies and compatibility",[200,1695,1696,1705],{},[203,1697,1698],{},[206,1699,1700,1702],{},[209,1701,225],{},[209,1703,1704],{},"Schema dependencies",[218,1706,1707,1716,1728],{},[206,1708,1709,1713],{},[223,1710,1711],{},[103,1712,230],{},[223,1714,1715],{},"kyo-schema 1.0.0-RC7. Add kyo-schema-json and kyo-schema-yaml yourself for text formats",[206,1717,1718,1722],{},[223,1719,1720],{},[103,1721,235],{},[223,1723,1724,1725,1727],{},"zio-schema 1.7.5. Add zio-schema-derivation 1.7.5 for ",[103,1726,963],{},", and zio-schema-json for JSON text",[206,1729,1730,1738],{},[223,1731,1732,167,1735],{},[103,1733,1734],{},"kyo-h3-ext",[103,1736,1737],{},"zio-h3-ext",[223,1739,1740],{},"None. The handler modules never bring a schema library",[99,1742,1743,1744,1747],{},"Both bridges use Scala 3.9.0 and NativeConverter 0.9.0. See ",[190,1745,1746],{"href":87},"compatibility"," for the tested profile.",[99,1749,1750],{},"What is tested:",[906,1752,1753,1774,1792],{},[909,1754,1755,1756,1759,1760,1763,1764,1766,1767,1769,1770,1773],{},"Kyo bridge (",[103,1757,1758],{},"NativeSchemaSuite",", 30 tests with ",[103,1761,1762],{},"H3BodySuite","): TypeScript types of records, sums, numbers, scalars and collections checked against the encoder output, and ",[103,1765,1527],{}," for a fluent rename at the root and in a nested type; named models for records and sums, a generic instantiation written out, and a recursive model that stays ",[103,1768,1527],{},"; wire equality with kyo-schema-json for records, options, enums, sealed traits, collections, numeric edges, big numbers (and their length and exponent limits), times and bytes; strict decoding; validation messages and paths; no input values in messages; no JSON text round trip; no blanket instance; JSON and YAML round trips from the same schema; ",[103,1771,1772],{},"secretSchema","; HTTP 422 entries. ",[909,1775,1776,1777,1780,1781,1783,1784,1787,1788,1791],{},"ZIO bridge (",[103,1778,1779],{},"NativeSchemaSpec",", 24 tests, with ",[103,1782,1772],{},", the TypeScript types of records, options, wire names, transient fields, transforms and recursion, named models after the ",[103,1785,1786],{},"TypeId",", and sealed traits that stay unsupported) and ZIO request bodies (",[103,1789,1790],{},"RequestBodySpec","): supported shapes, transforms, accumulated entries with paths, and the 400\u002F422 statuses. ",[909,1793,1794,1795,771,1798,1801,1802,193],{},"The demo's Kyo routes answered 422 with ",[103,1796,1797],{},"must not be blank",[103,1799,1800],{},"length must be \u003C= 80"," over an h3 server; see ",[190,1803,1746],{"href":87},[1805,1806,1807],"style",{},"html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":120,"searchDepth":413,"depth":413,"links":1809},[1810,1811,1815,1816,1817,1818,1819,1820],{"id":197,"depth":413,"text":198},{"id":367,"depth":413,"text":368,"children":1812},[1813,1814],{"id":735,"depth":426,"text":736},{"id":903,"depth":426,"text":904},{"id":952,"depth":413,"text":953},{"id":1402,"depth":413,"text":900},{"id":1558,"depth":413,"text":1559},{"id":1592,"depth":413,"text":1593},{"id":1673,"depth":413,"text":1674},{"id":1692,"depth":413,"text":1693},"Derive the native value, JSON, YAML and validation from one schema per model, with Kyo Schema or ZIO Schema.","md",null,{},{"title":39,"description":1821},"TX__rz1CTcUzdMEAK6Sj6WglCOuOktc0ro7FV1NQzzM",[1828,1830],{"title":35,"path":36,"stem":37,"description":1829,"children":-1},"Open request resources in the request scope and application resources once, with Shared or ZShared and the Nitro close hook.",{"title":43,"path":44,"stem":45,"description":1831,"children":-1},"Use kyo-sql or Skunk directly inside Nitro, with one pool per application and one transaction or session per request.",1792533383165]