View
6.833
Download
0
Category
Tags:
Preview:
Citation preview
JSON OBJECTS RDBMSTO TO
Stephen Kemmerling@42eng
CONTACTS AS A SERVICE
Should have JSON endpoints for• Store contact information
• Retrieval by Name
Contacts as a Service
https://github.com/FortyTwoEng/Contacts-As-A-Service/blob/master/app/controllers/Application.scala
•OO Representation
•Handle JSON requests and convert to OO
•Save to DB/Load from DB
What do we need?
• OO Representation
•Handle JSON requests and convert to OO
•Save to DB/Load from DB
What do we need?
SCALA REPRESENTATION
case class Email(addr: String)
case class Contact( name: String, phone: Option[Int], email: Option[Email])
•OO Representation
• Handle JSON requests and convert to OO
•Save to DB/Load from DB
What do we need?
SENDING JSON RESPONSES
def lookup(name: String) = Action { request => val contacts : Seq[Contact] = loadFromDb(name) val contactsJson : Seq[JsValue] = contacts.map(Json.toJson(_)) Ok(JsArray(contactsJson))}
TO/FROM JSON
trait Format[T] { def reads(json: JsValue): JsResult[T] def writes(obj: T): JsValue}
MACROS!
object Contact { implicit val format: Format[Contact] = Json.format[Contact]}
Almost, but not quite: Can’t deal with Email
case class Email(addr: String)
case class Contact( name: String, phone: Option[Int], email: Option[Email])
MAGIC!
FORMAT BY HAND
object Email { implicit format : Format[Email] = Json.format[Email]}
Let’s not be lazy
FORMAT BY HANDobject Email { implicit val format = new Format[Email]{ def reads(json: JsValue) : JsResult[Email] = { json match{ case JsString(s) => JsSuccess(Email(s)) case _ => JsError() } }
def writes(email: Email) : JsValue = { JsString(email.addr) } }}
ACCEPTING JSON REQUESTS
def store(name: String) = Action(parse.tolerantJson) { request => val phoneJson : JsValue = request.body \ "phone" val phone : Option[Int] = phoneJson.asOpt[Int] val email = (request.body \ "email").asOpt[Email] val contact = Contact(name, phone, email) saveToDb(contact)
Ok(“”)}
ALL TOGETHER NOWdef lookup(name: String) = Action { request => val contacts : Seq[Contact] = loadFromDb(name) val contactsJson : Seq[JsValue] = contacts.map(Json.toJson(_)) Ok(JsArray(contactsJson))}
def store(name: String) = Action(parse.tolerantJson) { request => val phoneJson : JsValue = request.body \ "phone" val phone : Option[Int] = phoneJson.asOpt[Int] val email = (request.body \ "email").asOpt[Email] val contact = Contact(name, phone, email) saveToDb(contact) Ok(“”)}
•OO Representation
•Handle JSON requests and convert to OO
• Save to DB/Load from DB
What do we need?
SLICK TABLE DEFINITION
object Contacts extends Table[Contact]("contacts") { def name = column[String]("name", O.PrimaryKey) def phone = column[Int]("phone", O.Nullable) def email = column[Email]("email", O.Nullable) def * = name ~ phone.? ~ email.? <> (Contact.apply _, Contact.unapply _)}
INSERTS AND LOOKUPS
def saveToDb(contact: Contact) = database.withSession{ implicit session: Session => Contacts.*.insert(contact) }
def loadFromDb(name: String) = database.withSession{ implicit session: Session => (for (row <- Contacts if row.name===name) yield row).list}
SLICK TABLE DEFINITIONobject Contacts extends Table[Contact]("contacts") { def name = column[String]("name", O.PrimaryKey) def phone = column[Int]("phone", O.Nullable) def email = column[Email]("email", O.Nullable) def * = name ~ phone.? ~ email.? <> (Contact.apply _, Contact.unapply _)}
def saveToDb(contact: Contact) = database.withSession{ implicit session: Session => Contacts.*.insert(contact) }
def loadFromDb(name: String) = database.withSession{ implicit session: Session => (for (row <- Contacts if row.name===name) yield row).list}
TYPE MAPPERimplicit object typeMapper extends BaseTypeMapper[Email] { def apply(profile: BasicProfile) : TypeMapperDelegate[Email] = { val delegate = profile.typeMapperDelegates.stringTypeMapperDelegate new TypeMapperDelegate[Email] { def sqlType = delegate.sqlType def setValue(value: Email, p: PositionedParameters) = delegate.setValue(value.addr, p) def setOption(valueOpt: Option[Email], p: PositionedParameters) = delegate.setOption(valueOpt.map(_.addr), p) def nextValue(r: PositionedResult): Email = Email(delegate.nextValue(r)) def sqlTypeName = delegate.sqlTypeName def updateValue(value: Email, r: PositionedResult) = delegate.updateValue(value.addr, r) def zero = Email("towel@42go.com") } }}
case class Email(addr: String)
object Email { implicit val format = new
Format[Email]{ def reads(json: JsValue) :
JsResult[Email] = { json match{ case JsString(s) =>
JsSuccess(Email(s)) case _ => JsError()
} } def writes(email: Email) :
JsValue = { JsString(email.addr)
}
lookup(name: String) =
Action(parse.json) { request =>
contacts : Seq[Contact] =
loadFromDb(name) contactsJson : Seq[JsValue] =
contacts.map(Json.toJson(_))
Ok(JsArray(contactsJson)) store(name: String)
parse.json
object Contacts extends
Table[Contact]("contacts") {
def name = column[String]
("name", O.PrimaryKey)
def phone = column[Int]
("phone", O.Nullable) def email = column[Email]
("email", O.Nullable) def * = name ~ phone.? ~
email.? <> (Contact.apply _,
Contact.unapply _)}
def saveToDb(contact: Contact) =
database.withSession{ implicit
session: Session => Contacts.*.insert(contact
}
def
p: PositionedParameters) =
addr, p)
setOption(valueOpt: Option[Email], p:
PositionedParameters) = delegate.setOption(valueOpt.map(_.addr),
def nextValue(r: PositionedResult): Email =
Email(delegate.nextValue(r))
def sqlTypeName = delegate.sqlTypeName
def updateValue(value: Email, r: PositionedResult) =
delegate.updateValue(value.addr, r)
def zero = Email("towel@42go.com")
} }}
case class Contact( name: String, phone: Option[Int], email: Option[Email]
)
object Contact { implicit format : Format[Contact] = Json.
}
SOURCE: https://github.com/FortyTwoEng/Contacts-As-A-ServiceFOLLOW US: @42ENGJOIN US: 42GO.COM/JOIN_US.HTML
Recommended