Skip to content

Commit 654d36f

Browse files
committed
Add basic server
0 parents  commit 654d36f

File tree

10 files changed

+245
-0
lines changed

10 files changed

+245
-0
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
logs
2+
target
3+
/.bsp
4+
/.idea
5+
/.idea_modules
6+
/.classpath
7+
/.project
8+
/.settings
9+
/RUNNING_PID
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package controllers
2+
3+
import scala.collection.mutable.Map
4+
5+
import javax.inject._
6+
import play.api._
7+
import play.api.libs.json._
8+
import play.api.mvc._
9+
10+
import io.github.dataunitylab.jsonoid.discovery.{DiscoverSchema, JsonoidParams}
11+
import io.github.dataunitylab.jsonoid.discovery.schemas.{
12+
JsonSchema,
13+
PropertySets,
14+
ZeroSchema
15+
}
16+
17+
import play.api.libs.{ json => pjson }
18+
import org.{ json4s => j4s }
19+
20+
object Conversions {
21+
def toJson4s(json: play.api.libs.json.JsValue):org.json4s.JValue = json match {
22+
case pjson.JsString(str) => j4s.JString(str)
23+
case pjson.JsNull => j4s.JNull
24+
case pjson.JsBoolean(value) => j4s.JBool(value)
25+
case pjson.JsNumber(value) => j4s.JDecimal(value)
26+
case pjson.JsArray(items) => j4s.JArray(items.map(toJson4s(_)).toList)
27+
case pjson.JsObject(items) => j4s.JObject(items.map { case (k, v) => k -> toJson4s(v)}.toList)
28+
}
29+
30+
def toPlayJson(json: org.json4s.JValue): play.api.libs.json.JsValue = json match {
31+
case j4s.JString(str) => pjson.JsString(str)
32+
case j4s.JNothing => pjson.JsNull
33+
case j4s.JNull => pjson.JsNull
34+
case j4s.JDecimal(value) => pjson.JsNumber(value)
35+
case j4s.JDouble(value) => pjson.JsNumber(value)
36+
case j4s.JInt(value) => pjson.JsNumber(BigDecimal(value))
37+
case j4s.JLong(value) => pjson.JsNumber(BigDecimal(value))
38+
case j4s.JBool(value) => pjson.JsBoolean(value)
39+
case j4s.JSet(fields) => pjson.JsArray(fields.toList.map(toPlayJson(_)))
40+
case j4s.JArray(fields) => pjson.JsArray(fields.map(toPlayJson(_)))
41+
case j4s.JObject(fields) => pjson.JsObject(fields.map { case (k, v) => k -> toPlayJson(v)}.toMap)
42+
}
43+
44+
def toPlayJson(json: org.json4s.JObject): play.api.libs.json.JsObject =
45+
pjson.JsObject(json.obj.map { case (k, v) => k -> toPlayJson(v)}.toMap)
46+
}
47+
48+
final case class SchemaParams(name: String, propSet: Option[String] = None)
49+
object SchemaParams {
50+
implicit val schemaParamsRead: Reads[SchemaParams] = Json.reads[SchemaParams]
51+
}
52+
import SchemaParams._
53+
54+
/**
55+
* This controller creates an `Action` to handle HTTP requests to the
56+
* application's home page.
57+
*/
58+
@Singleton
59+
class JsonoidController @Inject()(val cc: ControllerComponents) extends AbstractController(cc) {
60+
private val schemas = Map.empty[String, JsonSchema[_]]
61+
private val jsonoidParams = Map.empty[String, JsonoidParams]
62+
63+
def status() = Action { implicit request: Request[AnyContent] =>
64+
Ok(Json.obj("status" -> "ok"))
65+
}
66+
67+
def postSchema() = Action(parse.json) { implicit request =>
68+
val schemaParamsResult = request.body.validate[SchemaParams]
69+
schemaParamsResult.fold(
70+
errors => {
71+
BadRequest(Json.obj("status" -> "error", "error" -> JsError.toJson(errors)))
72+
},
73+
schemaParams => {
74+
if (schemas.contains(schemaParams.name)) {
75+
Conflict(Json.obj("error" -> "Schema already exists"))
76+
} else {
77+
val maybePropSet = schemaParams.propSet match {
78+
case Some("All") =>
79+
Some(PropertySets.AllProperties)
80+
case Some("Simple") =>
81+
Some(PropertySets.SimpleProperties)
82+
case Some("Min") =>
83+
Some(PropertySets.MinProperties)
84+
case Some(_) =>
85+
None
86+
case None =>
87+
Some(PropertySets.AllProperties)
88+
}
89+
maybePropSet match {
90+
case Some(propSet) =>
91+
schemas.put(schemaParams.name, ZeroSchema())
92+
jsonoidParams.put(
93+
schemaParams.name,
94+
JsonoidParams().withPropertySet(propSet)
95+
)
96+
Created(Json.obj("status" -> "ok"))
97+
case None =>
98+
BadRequest(Json.obj("error" -> "Invalid property set"))
99+
}
100+
}
101+
}
102+
)
103+
}
104+
105+
def deleteSchema(name: String) = Action { implicit request =>
106+
if (schemas.contains(name)) {
107+
schemas.remove(name)
108+
Ok(Json.obj("status" -> "ok"))
109+
} else {
110+
NotFound(Json.obj("error" -> "Schema not found"))
111+
}
112+
}
113+
114+
def getSchema(name: String) = Action { implicit request =>
115+
schemas.get(name) match {
116+
case Some(schema) => Ok(Json.obj("schema" -> Conversions.toPlayJson(schema.toJson())))
117+
case None => NotFound(Json.obj("error" -> "Schema not found"))
118+
}
119+
}
120+
121+
def putSchema(name: String) = Action(parse.json) { implicit request =>
122+
schemas.get(name) match {
123+
case Some(schema) =>
124+
assert(jsonoidParams.contains(name))
125+
val p = jsonoidParams.get(name).get
126+
val newSchema = DiscoverSchema.discoverFromValue(Conversions.toJson4s(request.body))(p)
127+
newSchema match {
128+
case Some(newSchema) =>
129+
schemas.put(name, schema.merge(newSchema)(p))
130+
Ok(Json.obj("status" -> "ok"))
131+
case None =>
132+
BadRequest(Json.obj("error" -> "Invalid schema"))
133+
}
134+
case None => NotFound(Json.obj("error" -> "Schema not found"))
135+
}
136+
}
137+
}

build.sbt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name := """jsonoid-server"""
2+
organization := "io.github.dataunitylab.jsonoid"
3+
4+
version := "1.0-SNAPSHOT"
5+
6+
lazy val root = (project in file(".")).enablePlugins(PlayScala)
7+
8+
scalaVersion := "2.13.16"
9+
10+
libraryDependencies += guice
11+
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.1" % Test
12+
libraryDependencies += "io.github.dataunitylab" %% "jsonoid-discovery" % "0.30.1"
13+
libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.17.1"
14+
libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.17.1"
15+
16+
// Adds additional packages into Twirl
17+
//TwirlKeys.templateImports += "io.github.dataunitylab.jsonoid.controllers._"
18+
19+
// Adds additional packages into conf/routes
20+
// play.sbt.routes.RoutesKeys.routesImport += "io.github.dataunitylab.jsonoid.binders._"

build.sc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import mill._
2+
import $ivy.`com.lihaoyi::mill-contrib-playlib:`, mill.playlib._
3+
4+
object jsonoidserver extends RootModule with PlayModule {
5+
6+
def scalaVersion = "2.13.16"
7+
def playVersion = "3.0.6"
8+
def twirlVersion = "2.0.1"
9+
10+
object test extends PlayTests
11+
}

conf/application.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# https://www.playframework.com/documentation/latest/Configuration
2+
play.filters.hosts {
3+
allowed = ["."]
4+
}

conf/logback.xml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
4+
5+
<!DOCTYPE configuration>
6+
7+
<configuration>
8+
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
9+
<import class="ch.qos.logback.classic.AsyncAppender"/>
10+
<import class="ch.qos.logback.core.FileAppender"/>
11+
<import class="ch.qos.logback.core.ConsoleAppender"/>
12+
13+
<appender name="FILE" class="FileAppender">
14+
<file>${application.home:-.}/logs/application.log</file>
15+
<encoder class="PatternLayoutEncoder">
16+
<charset>UTF-8</charset>
17+
<pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) %cyan(%logger{36}) %magenta(%X{pekkoSource}) %msg%n</pattern>
18+
</encoder>
19+
</appender>
20+
21+
<appender name="STDOUT" class="ConsoleAppender">
22+
<!--
23+
On Windows, enabling Jansi is recommended to benefit from color code interpretation on DOS command prompts,
24+
which otherwise risk being sent ANSI escape sequences that they cannot interpret.
25+
See https://logback.qos.ch/manual/layouts.html#coloring
26+
-->
27+
<!-- <withJansi>true</withJansi> -->
28+
<encoder class="PatternLayoutEncoder">
29+
<charset>UTF-8</charset>
30+
<pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) %cyan(%logger{36}) %magenta(%X{pekkoSource}) %msg%n</pattern>
31+
</encoder>
32+
</appender>
33+
34+
<appender name="ASYNCFILE" class="AsyncAppender">
35+
<appender-ref ref="FILE"/>
36+
</appender>
37+
38+
<appender name="ASYNCSTDOUT" class="AsyncAppender">
39+
<appender-ref ref="STDOUT"/>
40+
</appender>
41+
42+
<logger name="play" level="INFO"/>
43+
<logger name="application" level="DEBUG"/>
44+
45+
<root level="WARN">
46+
<appender-ref ref="ASYNCFILE"/>
47+
<appender-ref ref="ASYNCSTDOUT"/>
48+
</root>
49+
50+
</configuration>

conf/messages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# https://www.playframework.com/documentation/latest/ScalaI18N

conf/routes

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Routes
2+
# This file defines all application routes (Higher priority routes first)
3+
# https://www.playframework.com/documentation/latest/ScalaRouting
4+
# ~~~~
5+
6+
GET /status controllers.JsonoidController.status()
7+
POST /schemas controllers.JsonoidController.postSchema()
8+
DELETE /schemas/:name controllers.JsonoidController.deleteSchema(name: String)
9+
GET /schemas/:name controllers.JsonoidController.getSchema(name: String)
10+
PUT /schemas/:name controllers.JsonoidController.putSchema(name: String)

project/build.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sbt.version=1.10.9

project/plugins.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.6")
2+
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.17.0")

0 commit comments

Comments
 (0)