Skip to content

Commit

Permalink
Make @postJson handle incoming JSON in a streaming manner, introduc…
Browse files Browse the repository at this point in the history
…e `@postJsonCached` (#123)
  • Loading branch information
lihaoyi committed May 18, 2024
1 parent 1b13abc commit 0ef3c59
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 14 deletions.
19 changes: 5 additions & 14 deletions cask/src/cask/endpoints/JsonEndpoint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,17 @@ object JsonData extends DataCompanion[JsonData]{
}
}

class postJson(val path: String, override val subpath: Boolean = false)
class postJsonCached(path: String, subpath: Boolean = false) extends postJsonBase(path, subpath, true)
class postJson(path: String, subpath: Boolean = false) extends postJsonBase(path, subpath, false)
abstract class postJsonBase(val path: String, override val subpath: Boolean = false, cacheBody: Boolean = false)
extends HttpEndpoint[Response[JsonData], ujson.Value]{
val methods = Seq("post")
type InputParser[T] = JsReader[T]

def wrapFunction(ctx: Request,
delegate: Delegate): Result[Response.Raw] = {
def wrapFunction(ctx: Request, delegate: Delegate): Result[Response.Raw] = {
val obj = for{
str <-
try {
val boas = new ByteArrayOutputStream()
Util.transferTo(ctx.exchange.getInputStream, boas)
Right(new String(boas.toByteArray))
}
catch{case e: Throwable => Left(cask.model.Response(
"Unable to deserialize input JSON text: " + e + "\n" + Util.stackTraceString(e),
statusCode = 400
))}
json <-
try Right(ujson.read(str))
try Right(ujson.read(if (cacheBody) ctx.bytes else ctx.exchange.getInputStream))
catch{case e: Throwable => Left(cask.model.Response(
"Input text is invalid JSON: " + e + "\n" + Util.stackTraceString(e),
statusCode = 400
Expand Down
1 change: 1 addition & 0 deletions cask/src/cask/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ package object cask {
type staticFiles = endpoints.staticFiles
type staticResources = endpoints.staticResources
type postJson = endpoints.postJson
type postJsonCached = endpoints.postJsonCached
type getJson = endpoints.getJson
type postForm = endpoints.postForm
type options = endpoints.options
Expand Down
11 changes: 11 additions & 0 deletions example/formJsonPost/app/src/FormJsonPost.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ object FormJsonPost extends cask.MainRoutes{
)
}

@cask.postJsonCached("/json-obj-cached")
def jsonEndpointObjCached(value1: ujson.Value, value2: Seq[Int], request: cask.Request) = {
ujson.Obj(
"value1" -> value1,
"value2" -> value2,
// `cacheBody = true` buffers up the body of the request in memory before parsing,
// giving you access to the request body data if you want to use it yourself
"body" -> request.text()
)
}

@cask.postForm("/form")
def formEndpoint(value1: cask.FormValue, value2: Seq[Int]) = {
"OK " + value1 + " " + value2
Expand Down
13 changes: 13 additions & 0 deletions example/formJsonPost/app/test/src/ExampleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ object ExampleTests extends TestSuite{
)
ujson.read(response2.text()) ==> ujson.Obj("value1" -> true, "value2" -> ujson.Arr(3))


val response2Cached = requests.post(
s"$host/json-obj-cached",
data = """{"value1": true, "value2": [3]}"""
)
ujson.read(response2Cached.text()) ==>
ujson.Obj(
"value1" -> true,
"value2" -> ujson.Arr(3),
"body" -> """{"value1": true, "value2": [3]}"""
)


val response3 = requests.post(
s"$host/form",
data = Seq("value1" -> "hello", "value2" -> "1", "value2" -> "2")
Expand Down
1 change: 1 addition & 0 deletions example/httpMethods/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ trait AppModule extends CrossScalaModule{
ivy"com.lihaoyi::utest::0.8.1",
ivy"com.lihaoyi::requests::0.8.0",
)
def forkArgs = Seq("--add-opens=java.base/java.net=ALL-UNNAMED")
}
}

0 comments on commit 0ef3c59

Please sign in to comment.