I am using openapi 3.0.3 with sbt. I need to add an optional array query parameter in on endpoint. GroupBy parameter is not necessary, there could be minimum 0 or max 2 values. Here's what I have done -
parameters:
- name: groupBy
in: query
description: Group by
required: false
schema:
type: array
items:
type: string
When I use sbt openApiGenerate the following method signature is generated -
def getStats(repoHrn: String, groupBy: String)
(implicit toEntityMarshallerBadRequestDetails: ToEntityMarshaller[BadRequestDetails], toEntityMarshallerIdStat: ToEntityMarshaller[IdStat]): Route
I need it to be generated as -
def getStats(repoHrn: String, groupBy: Option[Array[String]])
(implicit toEntityMarshallerBadRequestDetails: ToEntityMarshaller[BadRequestDetails], toEntityMarshallerIdStat: ToEntityMarshaller[IdStat]): Route
I tried several things, nothing seems to work.
I read the doc but I don't know what is something I am missing here.
Related
I'm using reactivemongo in my Play Framework App and I noticed that all documents represented as for example
{name: "Robert", age: 41 }
are stored in MongoDB as
{_id: { $oid:"574005977e356b7310bcdc8d"}, name: "Robert", age: 41 }
and that's fine. That's the method I use to save the documents
// Scala code
def save(document: JsObject)
(implicit ec: ExecutionContext): Future[WriteResult] = {
collection.insert(document)
}
The latter representation is also what I get when I fetch the same document from the DB, using this method:
def find(query: JsObject, queryOptions: QueryOpts, projection: JsObject,
sort: JsObject, pageSize: Int)
(implicit ec: ExecutionContext): Future[List[JsObject]] = {
collection.find(query, projection)
.options(queryOptions)
.sort(sort)
.cursor[JsObject](ReadPreference.primaryPreferred)
.collect[List](pageSize)
}
but in this case I'd like to get a representation like
{_id: "574005977e356b7310bcdc8d", name: "Robert", age: 41 }
in order to send the documents to the requesting client via my ReSTful API. How can I get this?
You can use Json transformers: Case 6: Prune a branch from input JSON
...
.collect[List](pageSize)
.map(JsArray)
.map(
_.transform(
Reads.list(
(__\"_id").json.prune
)
)
)
... tranform JsResult to your needs
First let me say that the following representation is not what is stored in the MongoDB, which is using BSON, but what is serialized using the JSON extended syntax (see JSON documentation for ReactiveMongo).
Then, when using .cursor[T] on a query build, you are free to provide a custom document reader (in the implicit scope).
When using the JSON serialization pack, it means providing the appropriate Reads[T].
I would also add that the function .find and .save are essentially what is already done by the ReactiveMongo Collection API.
I have the following case classes:
case class DataEntity
(
name: String,
value: Either[Complex, String]
)
case class Complex (x: String, y: String)
As far as I can see, serialization (writing to MongoDB) goes fine, but it fails in deserializing:
com.novus.salat.util.ToObjectGlitch:
argument type mismatch
$anon$2(class catalog.DataEntity # com.novus.salat.global.package$$anon$1#3fa48431) toObject failed on:
SYM: catalog.DataEntity
CONSTRUCTOR
public catalog.DataEntity(java.lang.String,scala.util.Either<catalog.Complex, java.lang.String>)
---------- CONSTRUCTOR EXPECTS FOR PARAM [0] --------------
NAME: name
TYPE: java.lang.String
DEFAULT ARG [Missing, but unnecessary because input value was supplied]
#Ignore false
---------- CONSTRUCTOR INPUT ------------------------
TYPE: java.lang.String
VALUE:
TESTTEXT
------------------------------------------------------------
---------- CONSTRUCTOR EXPECTS FOR PARAM [1] --------------
NAME: value
TYPE: scala.util.Either<catalog.Complex, java.lang.String>
DEFAULT ARG [Missing, but unnecessary because input value was supplied]
#Ignore false
---------- CONSTRUCTOR INPUT ------------------------
TYPE: com.mongodb.BasicDBList
VALUE:
[ [ "File" , "/bin/ls" ...
------------------------------------------------------------
The output above is manually matched to the simplified case classes above.
I am using salatDAO for reading and writing to DB.
Either is not currently supported. I've updated the "Supported Types" wiki accordingly.
Note that in Salat 1.10.0-SNAPSHOT, you will get an error like the following (when attempting to deserialize from JSON strings):
scala> SalatExamples.eitherHolder()
serialized EitherHolder(Left(data)) to { "_typeHint" : "com.novus.salat.examples.EitherHolder" , "either" : [ "data"]} for storage in mongo
com.novus.salat.json.UnsupportedJsonTransformationException: serialize: Unsupported JSON transformation for class='scala.util.Left', value='Left(data)'
NOTE: salat has certain limitations. It cannot deserialize JSON into case classes having fields such as:
- Arrays such as Array[String]
- Nested collections such as Map[String, List[String]]
- Optional collections such as Option[List[String]]
For more information, please visit: https://github.com/salat/salat/wiki/SupportedTypes
https://github.com/salat/salat/wiki/SupportedTypes
See also: https://github.com/noahlz/salat-examples/blob/master/src/main/scala/com/novus/salat/examples/SalatExamples.scala
I have an Action with optional params that looks like this:
def editLink(storyId: Long, linkId: Long, thumbnail: Option[String], title: Option[String], description: Option[String], hidden: Option[Boolean]) = Action.async { ... }
This action is exposed as a JSRoute. I had assumed that providing null as a param to the javascript route from JavaScript would map to Scala's None, but that appears to be incorrect and, instead, it translates to a literal "null" String. How can I indicate that certain query parameters are None when using this action from JavaScript?
Javascript, this wonderful language has two keywords usually used to define the absence of something. null is one of them, undefined is another one. Knowing that when you omit a parameter in a function, it gets passed as undefined, I would imagine that this is what you should use for an optional parameter. As an example :
var f = function (param, optionalParam) {
console.log(optionalParam);
}
f(1, 2); // prints 2
f(1); // prints undefined
I have a field.scala.html that should take a control as input and render it.
Right now I do like this:
#field("shop", "name", true) { (modelName, fieldName, required) =>
#textInput(modelName, fieldName, required)
}
But I would like to do it like this:
#field("shop", "name", true)(textInput)
I see 2 ways it could be done but not sure if it's possible:
Somehow via reflection call the textInput.apply with appropriate
parameters.
Make textInput implement some trait and field would
require an instance of this particular trait (more type safe)
Maybe there is a better way?
Templates are just functions. If field.scala.html takes a:
(String, String, Boolean) => Html
And textInput.Scala.html has the following parameter declaration:
#(modelName: String, fieldName: String, required: Boolean)
Then what you want to do will just work. If not try passing textInput.apply.
In my Play 2 controller (Scala) I've a method that looks like the following.
start(id:String, keywords:Option[List[String]])
Basically I want to get pass a list of string as keywords where it's optional.
The following doesn't work and gives me a compile error.
GET /start start(id:String,options:Option[List[String]])
The error makes sense because even if this route compiled I'm not sure how I would pass a list of Strings in my GET URL.
I'm looking for suggestions to resolve this.
Since you're just using keywords, how about comma-separated values in the query string?
GET /start/:id controllers.Sample.start(id: String, options: Option[String])
/start/1233?options=key,word,test
Then in your controller convert to Option[List[String]]:
def start(id: String, options: Option[String]) = Action {
val opts: Option[List[String]] = options.map(_.split(',').filter(_.nonEmpty))
...
}