/** * Generated by API Builder - https://www.apibuilder.io * Service version: 0.2.6 * User agent: apibuilder app.apibuilder.io/bombas/storeback-api/0.2.6/ning_1_9_client */ package bombas.storeback.api.v0.models { /** * @param name The name of the breadcrumb section * @param link Pieces of a collections page url to use for link * @param position Order position */ final case class Breadcrumb( name: _root_.scala.Option[String] = None, link: _root_.scala.Option[String] = None, position: _root_.scala.Option[Int] = None ) /** * @param id The slug id of the color * @param position The order in which the color should be displayed * @param name The name of the color * @param fill A 80x80 url of an image of the swatch to use on FE */ final case class Color( id: _root_.scala.Option[String] = None, position: _root_.scala.Option[Int] = None, name: _root_.scala.Option[String] = None, fill: _root_.scala.Option[String] = None ) /** * @param iconHandle the name used to generate the silhouette icon image for a product detail * @param title the title of the details / set of tech features */ final case class Detail( iconHandle: _root_.scala.Option[String] = None, title: _root_.scala.Option[String] = None, tech: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Tech]] = None ) /** * @param id A unique numeric identifier for the product image. * @param position The order of the product image in the list. The first product image is at * position 1 and is the 'main' image for the product. * @param alt ALT text * @param src Specifies the location of the product image. This parameter supports URL filters * that you can use to retrieve modified copies of the image. For example, add * _small, to the filename to retrieve a scaled copy of the image at 100 x 100 px * (for example, ipod-nano_small.png), or add _2048x2048 to retrieve a copy of the * image constrained at 2048 x 2048 px resolution (for example, * ipod-nano_2048x2048.png). */ final case class Image( id: _root_.scala.Option[Int] = None, position: _root_.scala.Option[Int] = None, alt: _root_.scala.Option[String] = None, src: _root_.scala.Option[String] = None ) /** * @param msrp The original price of the item before an adjustment or a sale. * @param price The price of the product variant. * @param isDiscounted true If the product is discounted * @param percentOff percentOff which is a whole number as a string, based on the percentage price is * off of msrp prices. */ final case class Price( msrp: _root_.scala.Option[String] = None, price: _root_.scala.Option[String] = None, isDiscounted: _root_.scala.Option[Boolean] = None, percentOff: _root_.scala.Option[String] = None ) /** * @param id An unsigned 64-bit integer that's used as a unique identifier for the product. * Each id is unique across the Shopify system. No two products will have the same * id, even if they're from different shops. * @param title The name of the product. * @param handle A unique human-friendly string for the product. Automatically generated from the * product's title. Used by the Liquid templating language to refer to objects. * @param description A description of the product. * @param descriptionHtml A description of the product. Supports HTML formatting. * @param itemCount The number of units included. If it is > 1, then it is a pack. * @param productType The product type * @param gender The marketed gender of the products * @param createdAt The date and time (ISO 8601 format) when the product was created. * @param updatedAt The date and time (ISO 8601 format) when the product was last modified. */ final case class Product( id: _root_.scala.Option[Long] = None, title: _root_.scala.Option[String] = None, handle: _root_.scala.Option[String] = None, description: _root_.scala.Option[String] = None, descriptionHtml: _root_.scala.Option[String] = None, itemCount: _root_.scala.Option[Int] = None, productType: _root_.scala.Option[String] = None, gender: _root_.scala.Option[String] = None, colors: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Color]] = None, sizes: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Size]] = None, images: _root_.scala.Option[Seq[_root_.play.api.libs.json.JsObject]] = None, variants: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Variant]] = None, breadcrumbs: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Breadcrumb]] = None, details: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Detail]] = None, createdAt: _root_.scala.Option[String] = None, updatedAt: _root_.scala.Option[String] = None ) /** * @param requiresShipping This property is deprecated. Use the `requires_shipping` property on the * InventoryItem resource instead. * @param grams The weight of the product variant in grams. * @param weight The weight of the product variant in the unit system specified with weight_unit. * @param weightUnit The unit of measurement that applies to the product variant's weight. If you * don't specify a value for weight_unit, then the shop's default unit of * measurement is applied. Valid values: g, kg, oz, and lb. */ final case class Shipping( requiresShipping: _root_.scala.Option[Boolean] = None, grams: _root_.scala.Option[Int] = None, weight: _root_.scala.Option[Int] = None, weightUnit: _root_.scala.Option[String] = None ) /** * A particular size options for a product * * @param name The name of the option which this size was created from */ final case class Size( name: _root_.scala.Option[String] = None, values: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.SizeValues]] = None ) /** * @param id The internal name of the size * @param name The visual name of the size * @param guidance Size related guidance for more specific examples for the user */ final case class SizeValues( id: _root_.scala.Option[String] = None, name: _root_.scala.Option[String] = None, guidance: _root_.scala.Option[String] = None ) /** * @param title name of the tech feature * @param handle a unique internal name used to identify the tech feature * @param content the copy wrote for the tech feature */ final case class Tech( title: _root_.scala.Option[String] = None, handle: _root_.scala.Option[String] = None, content: _root_.scala.Option[String] = None ) /** * @param id The unique numeric identifier for the product variant. * @param productId The unique numeric identifier for the product. * @param sku A unique identifier for the product variant in the shop. Required in order to * connect to a FulfillmentService. * @param title The title of the product variant. * @param isAvailable If the variant is availabor not * @param createdAt The date and time (ISO 8601 format) when the product was created. * @param updatedAt The date and time (ISO 8601 format) when the product was last modified. */ final case class Variant( id: _root_.scala.Option[Long] = None, productId: _root_.scala.Option[Long] = None, sku: _root_.scala.Option[String] = None, title: _root_.scala.Option[String] = None, isAvailable: _root_.scala.Option[Boolean] = None, price: _root_.scala.Option[bombas.storeback.api.v0.models.Price] = None, shipping: _root_.scala.Option[bombas.storeback.api.v0.models.Shipping] = None, createdAt: _root_.scala.Option[String] = None, updatedAt: _root_.scala.Option[String] = None, sizes: _root_.scala.Option[Seq[bombas.storeback.api.v0.models.Size]] = None ) } package bombas.storeback.api.v0.models { package object json { import play.api.libs.json.__ import play.api.libs.json.JsString import play.api.libs.json.Writes import play.api.libs.functional.syntax._ import bombas.storeback.api.v0.models.json._ private[v0] implicit val jsonReadsUUID: play.api.libs.json.Reads[_root_.java.util.UUID] = __.read[String].map { str => _root_.java.util.UUID.fromString(str) } private[v0] implicit val jsonWritesUUID: play.api.libs.json.Writes[_root_.java.util.UUID] = (x: _root_.java.util.UUID) => play.api.libs.json.JsString(x.toString) private[v0] implicit val jsonReadsJodaDateTime: play.api.libs.json.Reads[_root_.org.joda.time.DateTime] = __.read[String].map { str => _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseDateTime(str) } private[v0] implicit val jsonWritesJodaDateTime: play.api.libs.json.Writes[_root_.org.joda.time.DateTime] = (x: _root_.org.joda.time.DateTime) => { play.api.libs.json.JsString(_root_.org.joda.time.format.ISODateTimeFormat.dateTime.print(x)) } private[v0] implicit val jsonReadsJodaLocalDate: play.api.libs.json.Reads[_root_.org.joda.time.LocalDate] = __.read[String].map { str => _root_.org.joda.time.format.ISODateTimeFormat.dateTimeParser.parseLocalDate(str) } private[v0] implicit val jsonWritesJodaLocalDate: play.api.libs.json.Writes[_root_.org.joda.time.LocalDate] = (x: _root_.org.joda.time.LocalDate) => { play.api.libs.json.JsString(_root_.org.joda.time.format.ISODateTimeFormat.date.print(x)) } implicit def jsonReadsStorebackApiBreadcrumb: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Breadcrumb] = { for { name <- (__ \ "name").readNullable[String] link <- (__ \ "link").readNullable[String] position <- (__ \ "position").readNullable[Int] } yield Breadcrumb(name, link, position) } def jsObjectBreadcrumb(obj: bombas.storeback.api.v0.models.Breadcrumb): play.api.libs.json.JsObject = { (obj.name match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x)) }) ++ (obj.link match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("link" -> play.api.libs.json.JsString(x)) }) ++ (obj.position match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("position" -> play.api.libs.json.JsNumber(x)) }) } implicit def jsonWritesStorebackApiBreadcrumb: play.api.libs.json.Writes[Breadcrumb] = { (obj: bombas.storeback.api.v0.models.Breadcrumb) => { bombas.storeback.api.v0.models.json.jsObjectBreadcrumb(obj) } } implicit def jsonReadsStorebackApiColor: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Color] = { for { id <- (__ \ "id").readNullable[String] position <- (__ \ "position").readNullable[Int] name <- (__ \ "name").readNullable[String] fill <- (__ \ "fill").readNullable[String] } yield Color(id, position, name, fill) } def jsObjectColor(obj: bombas.storeback.api.v0.models.Color): play.api.libs.json.JsObject = { (obj.id match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("id" -> play.api.libs.json.JsString(x)) }) ++ (obj.position match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("position" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.name match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x)) }) ++ (obj.fill match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("fill" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiColor: play.api.libs.json.Writes[Color] = { (obj: bombas.storeback.api.v0.models.Color) => { bombas.storeback.api.v0.models.json.jsObjectColor(obj) } } implicit def jsonReadsStorebackApiDetail: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Detail] = { for { iconHandle <- (__ \ "icon_handle").readNullable[String] title <- (__ \ "title").readNullable[String] tech <- (__ \ "tech").readNullable[Seq[bombas.storeback.api.v0.models.Tech]] } yield Detail(iconHandle, title, tech) } def jsObjectDetail(obj: bombas.storeback.api.v0.models.Detail): play.api.libs.json.JsObject = { (obj.iconHandle match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("icon_handle" -> play.api.libs.json.JsString(x)) }) ++ (obj.title match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("title" -> play.api.libs.json.JsString(x)) }) ++ (obj.tech match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("tech" -> play.api.libs.json.Json.toJson(x)) }) } implicit def jsonWritesStorebackApiDetail: play.api.libs.json.Writes[Detail] = { (obj: bombas.storeback.api.v0.models.Detail) => { bombas.storeback.api.v0.models.json.jsObjectDetail(obj) } } implicit def jsonReadsStorebackApiImage: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Image] = { for { id <- (__ \ "id").readNullable[Int] position <- (__ \ "position").readNullable[Int] alt <- (__ \ "alt").readNullable[String] src <- (__ \ "src").readNullable[String] } yield Image(id, position, alt, src) } def jsObjectImage(obj: bombas.storeback.api.v0.models.Image): play.api.libs.json.JsObject = { (obj.id match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("id" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.position match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("position" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.alt match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("alt" -> play.api.libs.json.JsString(x)) }) ++ (obj.src match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("src" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiImage: play.api.libs.json.Writes[Image] = { (obj: bombas.storeback.api.v0.models.Image) => { bombas.storeback.api.v0.models.json.jsObjectImage(obj) } } implicit def jsonReadsStorebackApiPrice: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Price] = { for { msrp <- (__ \ "msrp").readNullable[String] price <- (__ \ "price").readNullable[String] isDiscounted <- (__ \ "isDiscounted").readNullable[Boolean] percentOff <- (__ \ "percentOff").readNullable[String] } yield Price(msrp, price, isDiscounted, percentOff) } def jsObjectPrice(obj: bombas.storeback.api.v0.models.Price): play.api.libs.json.JsObject = { (obj.msrp match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("msrp" -> play.api.libs.json.JsString(x)) }) ++ (obj.price match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("price" -> play.api.libs.json.JsString(x)) }) ++ (obj.isDiscounted match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("isDiscounted" -> play.api.libs.json.JsBoolean(x)) }) ++ (obj.percentOff match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("percentOff" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiPrice: play.api.libs.json.Writes[Price] = { (obj: bombas.storeback.api.v0.models.Price) => { bombas.storeback.api.v0.models.json.jsObjectPrice(obj) } } implicit def jsonReadsStorebackApiProduct: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Product] = { for { id <- (__ \ "id").readNullable[Long] title <- (__ \ "title").readNullable[String] handle <- (__ \ "handle").readNullable[String] description <- (__ \ "description").readNullable[String] descriptionHtml <- (__ \ "description_html").readNullable[String] itemCount <- (__ \ "item_count").readNullable[Int] productType <- (__ \ "product_type").readNullable[String] gender <- (__ \ "gender").readNullable[String] colors <- (__ \ "colors").readNullable[Seq[bombas.storeback.api.v0.models.Color]] sizes <- (__ \ "sizes").readNullable[Seq[bombas.storeback.api.v0.models.Size]] images <- (__ \ "images").readNullable[Seq[_root_.play.api.libs.json.JsObject]] variants <- (__ \ "variants").readNullable[Seq[bombas.storeback.api.v0.models.Variant]] breadcrumbs <- (__ \ "breadcrumbs").readNullable[Seq[bombas.storeback.api.v0.models.Breadcrumb]] details <- (__ \ "details").readNullable[Seq[bombas.storeback.api.v0.models.Detail]] createdAt <- (__ \ "created_at").readNullable[String] updatedAt <- (__ \ "updated_at").readNullable[String] } yield Product(id, title, handle, description, descriptionHtml, itemCount, productType, gender, colors, sizes, images, variants, breadcrumbs, details, createdAt, updatedAt) } def jsObjectProduct(obj: bombas.storeback.api.v0.models.Product): play.api.libs.json.JsObject = { (obj.id match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("id" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.title match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("title" -> play.api.libs.json.JsString(x)) }) ++ (obj.handle match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("handle" -> play.api.libs.json.JsString(x)) }) ++ (obj.description match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("description" -> play.api.libs.json.JsString(x)) }) ++ (obj.descriptionHtml match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("description_html" -> play.api.libs.json.JsString(x)) }) ++ (obj.itemCount match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("item_count" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.productType match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("product_type" -> play.api.libs.json.JsString(x)) }) ++ (obj.gender match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("gender" -> play.api.libs.json.JsString(x)) }) ++ (obj.colors match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("colors" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.sizes match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("sizes" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.images match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("images" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.variants match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("variants" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.breadcrumbs match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("breadcrumbs" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.details match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("details" -> play.api.libs.json.Json.toJson(x)) }) ++ (obj.createdAt match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("created_at" -> play.api.libs.json.JsString(x)) }) ++ (obj.updatedAt match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("updated_at" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiProduct: play.api.libs.json.Writes[Product] = { (obj: bombas.storeback.api.v0.models.Product) => { bombas.storeback.api.v0.models.json.jsObjectProduct(obj) } } implicit def jsonReadsStorebackApiShipping: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Shipping] = { for { requiresShipping <- (__ \ "requires_shipping").readNullable[Boolean] grams <- (__ \ "grams").readNullable[Int] weight <- (__ \ "weight").readNullable[Int] weightUnit <- (__ \ "weight_unit").readNullable[String] } yield Shipping(requiresShipping, grams, weight, weightUnit) } def jsObjectShipping(obj: bombas.storeback.api.v0.models.Shipping): play.api.libs.json.JsObject = { (obj.requiresShipping match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("requires_shipping" -> play.api.libs.json.JsBoolean(x)) }) ++ (obj.grams match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("grams" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.weight match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("weight" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.weightUnit match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("weight_unit" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiShipping: play.api.libs.json.Writes[Shipping] = { (obj: bombas.storeback.api.v0.models.Shipping) => { bombas.storeback.api.v0.models.json.jsObjectShipping(obj) } } implicit def jsonReadsStorebackApiSize: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Size] = { for { name <- (__ \ "name").readNullable[String] values <- (__ \ "values").readNullable[Seq[bombas.storeback.api.v0.models.SizeValues]] } yield Size(name, values) } def jsObjectSize(obj: bombas.storeback.api.v0.models.Size): play.api.libs.json.JsObject = { (obj.name match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x)) }) ++ (obj.values match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("values" -> play.api.libs.json.Json.toJson(x)) }) } implicit def jsonWritesStorebackApiSize: play.api.libs.json.Writes[Size] = { (obj: bombas.storeback.api.v0.models.Size) => { bombas.storeback.api.v0.models.json.jsObjectSize(obj) } } implicit def jsonReadsStorebackApiSizeValues: play.api.libs.json.Reads[bombas.storeback.api.v0.models.SizeValues] = { for { id <- (__ \ "id").readNullable[String] name <- (__ \ "name").readNullable[String] guidance <- (__ \ "guidance").readNullable[String] } yield SizeValues(id, name, guidance) } def jsObjectSizeValues(obj: bombas.storeback.api.v0.models.SizeValues): play.api.libs.json.JsObject = { (obj.id match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("id" -> play.api.libs.json.JsString(x)) }) ++ (obj.name match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("name" -> play.api.libs.json.JsString(x)) }) ++ (obj.guidance match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("guidance" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiSizeValues: play.api.libs.json.Writes[SizeValues] = { (obj: bombas.storeback.api.v0.models.SizeValues) => { bombas.storeback.api.v0.models.json.jsObjectSizeValues(obj) } } implicit def jsonReadsStorebackApiTech: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Tech] = { for { title <- (__ \ "title").readNullable[String] handle <- (__ \ "handle").readNullable[String] content <- (__ \ "content").readNullable[String] } yield Tech(title, handle, content) } def jsObjectTech(obj: bombas.storeback.api.v0.models.Tech): play.api.libs.json.JsObject = { (obj.title match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("title" -> play.api.libs.json.JsString(x)) }) ++ (obj.handle match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("handle" -> play.api.libs.json.JsString(x)) }) ++ (obj.content match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("content" -> play.api.libs.json.JsString(x)) }) } implicit def jsonWritesStorebackApiTech: play.api.libs.json.Writes[Tech] = { (obj: bombas.storeback.api.v0.models.Tech) => { bombas.storeback.api.v0.models.json.jsObjectTech(obj) } } implicit def jsonReadsStorebackApiVariant: play.api.libs.json.Reads[bombas.storeback.api.v0.models.Variant] = { for { id <- (__ \ "id").readNullable[Long] productId <- (__ \ "product_id").readNullable[Long] sku <- (__ \ "sku").readNullable[String] title <- (__ \ "title").readNullable[String] isAvailable <- (__ \ "is_available").readNullable[Boolean] price <- (__ \ "price").readNullable[bombas.storeback.api.v0.models.Price] shipping <- (__ \ "shipping").readNullable[bombas.storeback.api.v0.models.Shipping] createdAt <- (__ \ "created_at").readNullable[String] updatedAt <- (__ \ "updated_at").readNullable[String] sizes <- (__ \ "sizes").readNullable[Seq[bombas.storeback.api.v0.models.Size]] } yield Variant(id, productId, sku, title, isAvailable, price, shipping, createdAt, updatedAt, sizes) } def jsObjectVariant(obj: bombas.storeback.api.v0.models.Variant): play.api.libs.json.JsObject = { (obj.id match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("id" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.productId match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("product_id" -> play.api.libs.json.JsNumber(x)) }) ++ (obj.sku match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("sku" -> play.api.libs.json.JsString(x)) }) ++ (obj.title match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("title" -> play.api.libs.json.JsString(x)) }) ++ (obj.isAvailable match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("is_available" -> play.api.libs.json.JsBoolean(x)) }) ++ (obj.price match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("price" -> bombas.storeback.api.v0.models.json.jsObjectPrice(x)) }) ++ (obj.shipping match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("shipping" -> bombas.storeback.api.v0.models.json.jsObjectShipping(x)) }) ++ (obj.createdAt match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("created_at" -> play.api.libs.json.JsString(x)) }) ++ (obj.updatedAt match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("updated_at" -> play.api.libs.json.JsString(x)) }) ++ (obj.sizes match { case None => play.api.libs.json.Json.obj() case Some(x) => play.api.libs.json.Json.obj("sizes" -> play.api.libs.json.Json.toJson(x)) }) } implicit def jsonWritesStorebackApiVariant: play.api.libs.json.Writes[Variant] = { (obj: bombas.storeback.api.v0.models.Variant) => { bombas.storeback.api.v0.models.json.jsObjectVariant(obj) } } } } package bombas.storeback.api.v0 { import com.ning.http.client.{AsyncCompletionHandler, AsyncHttpClient, Realm, Request, RequestBuilder, Response, AsyncHttpClientConfig} object Constants { val BaseUrl = "https://bombas-storeback-api.global.ssl.fastly.net/v1" val Namespace = "bombas.storeback.api.v0" val UserAgent = "apibuilder app.apibuilder.io/bombas/storeback-api/0.2.6/ning_1_9_client" val Version = "0.2.6" val VersionMajor = 0 } class Client( val baseUrl: String = "https://bombas-storeback-api.global.ssl.fastly.net/v1", auth: scala.Option[bombas.storeback.api.v0.Authorization] = None, defaultHeaders: Seq[(String, String)] = Nil, asyncHttpClient: AsyncHttpClient = Client.defaultAsyncHttpClient ) extends interfaces.Client { import org.slf4j.{Logger, LoggerFactory} import bombas.storeback.api.v0.models.json._ def closeAsyncHttpClient(): Unit = { asyncHttpClient.close() } val logger = LoggerFactory.getLogger(getClass) def products: Products = Products object Products extends Products { override def get( productId: String, requestHeaders: Seq[(String, String)] = Nil )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[bombas.storeback.api.v0.models.Product] = { _executeRequest("GET", s"/v1/products/${_root_.bombas.storeback.api.v0.PathSegment.encode(productId, "UTF-8")}", requestHeaders = requestHeaders).map { case r if r.getStatusCode == 200 => _root_.bombas.storeback.api.v0.Client.parseJson("bombas.storeback.api.v0.models.Product", r, _.validate[bombas.storeback.api.v0.models.Product]) case r if r.getStatusCode == 400 => throw bombas.storeback.api.v0.errors.UnitResponse(r.getStatusCode) case r if r.getStatusCode == 404 => throw bombas.storeback.api.v0.errors.UnitResponse(r.getStatusCode) case r => throw bombas.storeback.api.v0.errors.UnitResponse(r.getStatusCode) } } } def _logRequest(request: Request): Unit = { if (logger.isInfoEnabled) { logger.info("_logRequest: " + request) } } def _logResponse(response: Response): Unit = { if (logger.isInfoEnabled) { logger.info("_logResponse: status=" + response.getStatusCode + ", responseBody: " + response.getResponseBody("UTF-8")) } } def _requestBuilder(method: String, path: String, requestHeaders: Seq[(String, String)]): RequestBuilder = { val builder = new RequestBuilder(method) .setUrl(baseUrl + path) .addHeader("User-Agent", Constants.UserAgent) .addHeader("X-Apidoc-Version", Constants.Version) .addHeader("X-Apidoc-Version-Major", Constants.VersionMajor.toString) defaultHeaders.foreach { h => builder.addHeader(h._1, h._2) } requestHeaders.foreach { h => builder.addHeader(h._1, h._2) } auth.fold(builder) { case Authorization.Basic(username, passwordOpt) => { builder.setRealm( new Realm.RealmBuilder() .setPrincipal(username) .setPassword(passwordOpt.getOrElse("")) .setUsePreemptiveAuth(true) .setScheme(Realm.AuthScheme.BASIC) .build() ) } case a => sys.error("Invalid authorization scheme[" + a.getClass + "]") } } def _executeRequest( method: String, path: String, queryParameters: Seq[(String, String)] = Nil, requestHeaders: Seq[(String, String)] = Nil, body: Option[play.api.libs.json.JsValue] = None )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[com.ning.http.client.Response] = { val allHeaders = body match { case None => requestHeaders case Some(_) => _withJsonContentType(requestHeaders) } val request = _requestBuilder(method, path, allHeaders) queryParameters.foreach { pair => request.addQueryParam(pair._1, pair._2) } val requestWithParamsAndBody = body.fold(request) { b => val serialized = play.api.libs.json.Json.stringify(b) request.setBody(serialized) } val finalRequest = requestWithParamsAndBody.build() _logRequest(finalRequest) val result = scala.concurrent.Promise[com.ning.http.client.Response]() asyncHttpClient.executeRequest(finalRequest, new AsyncCompletionHandler[Unit]() { override def onCompleted(r: com.ning.http.client.Response) = { _logResponse(r) result.success(r) } override def onThrowable(t: Throwable) = result.failure(t) } ) result.future } /** * Adds a Content-Type: application/json header unless the specified requestHeaders * already contain a Content-Type header */ def _withJsonContentType(headers: Seq[(String, String)]): Seq[(String, String)] = { headers.find { _._1.toUpperCase == "CONTENT-TYPE" } match { case None => headers ++ Seq(("Content-Type" -> "application/json; charset=UTF-8")) case Some(_) => headers } } } object Client { private lazy val defaultAsyncHttpClient = { new AsyncHttpClient( new AsyncHttpClientConfig.Builder() .setExecutorService(java.util.concurrent.Executors.newCachedThreadPool()) .build() ) } def parseJson[T]( className: String, r: _root_.com.ning.http.client.Response, f: (play.api.libs.json.JsValue => play.api.libs.json.JsResult[T]) ): T = { f(play.api.libs.json.Json.parse(r.getResponseBody("UTF-8"))) match { case play.api.libs.json.JsSuccess(x, _) => x case play.api.libs.json.JsError(errors) => { throw bombas.storeback.api.v0.errors.FailedRequest(r.getStatusCode, s"Invalid json for class[" + className + "]: " + errors.mkString(" "), requestUri = Some(r.getUri.toJavaNetURI)) } } } } sealed trait Authorization extends _root_.scala.Product with _root_.scala.Serializable object Authorization { final case class Basic(username: String, password: Option[String] = None) extends Authorization } package interfaces { trait Client { def baseUrl: String def products: bombas.storeback.api.v0.Products } } trait Products { /** * Returns a product by ID or by handle. * The following API will return a product object sanitized of private information * from shopify. It should be thought of as a serializer or alturnative interface * to the public shopify information per a product. * * @param productId The ID or handle of the product to return. */ def get( productId: String, requestHeaders: Seq[(String, String)] = Nil )(implicit ec: scala.concurrent.ExecutionContext): scala.concurrent.Future[bombas.storeback.api.v0.models.Product] } package errors { import bombas.storeback.api.v0.models.json._ final case class UnitResponse(status: Int) extends Exception(s"HTTP $status") final case class FailedRequest(responseCode: Int, message: String, requestUri: Option[_root_.java.net.URI] = None) extends _root_.java.lang.Exception(s"HTTP $responseCode: $message") } object PathSegment { // See https://github.com/playframework/playframework/blob/2.3.x/framework/src/play/src/main/scala/play/utils/UriEncoding.scala def encode(s: String, inputCharset: String): String = { val in = s.getBytes(inputCharset) val out = new java.io.ByteArrayOutputStream() for (b <- in) { val allowed = segmentChars.get(b & 0xFF) if (allowed) { out.write(b) } else { out.write('%') out.write(upperHex((b >> 4) & 0xF)) out.write(upperHex(b & 0xF)) } } out.toString("US-ASCII") } private def upperHex(x: Int): Int = { // Assume 0 <= x < 16 if (x < 10) (x + '0') else (x - 10 + 'A') } private val segmentChars: java.util.BitSet = membershipTable(pchar) private def pchar: Seq[Char] = { val alphaDigit = for ((min, max) <- Seq(('a', 'z'), ('A', 'Z'), ('0', '9')); c <- min to max) yield c val unreserved = alphaDigit ++ Seq('-', '.', '_', '~') val subDelims = Seq('!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=') unreserved ++ subDelims ++ Seq(':', '@') } private def membershipTable(chars: Seq[Char]): java.util.BitSet = { val bits = new java.util.BitSet(256) for (c <- chars) { bits.set(c.toInt) } bits } } }