Http4s EntityDecoder not being auto derived for simple case class - circe

I am getting this error:
Cannot decode into a value of type com.blah.rest.model.UserProfile,
because no EntityDecoder[cats.effect.IO, com.blah.rest.model.UserProfile]
instance could be found.
for the following case class:
case class UserProfile(id: Option[Int], firstName: String, lastName: String)
Encountered the error on POST code:
case req # POST -> Root / "v1" / "profiles" =>
req.as[UserProfile] flatMap {(up: UserProfile) =>
Ok(service.createProfile(up).asJson)
}
With the following POST body:
{
"firstName": "Jack",
"lastName": "Appleseed"
}
I think this happens when the body is being converted to UserProfile in req.as[UserProfile]!
But, this is a plain vanilla case class, the EntityDecoder should be auto-derived! I know akka-http does it!
Any ideas/suggestions?
Please Note: Http4sVersion = "0.18.0-M4" and circe version "0.9.0-M1"

The answer is:
req.decodeJson[UserProfile] flatMap {(up: UserProfile) =>
Ok(service.createProfile(up).asJson)
}
The reason you get that is the bridge from a Circe decoder to an http4s EntityDecoder is not implicit. You can make one if you're purely a JSON API, but that's not an assumption the library can generally make.

Adding this dependency:
"io.circe" %% "circe-generic" % "0.9.1"
resolved the auto-encoding of case classes to JSON for me.
It allows for the required import: import io.circe.generic.auto._

Related

How to send a List<Map<String, String>> as parameter for a GET API

I have a requirement to pass List<Map<String, String>> as a parameter for REST GET API.
I need help to know how this can be passed from Postman or similar tool.
I tried to set it as a BODY for a GET API, it is giving me errors.
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.
Any help is appreciated.
You can very well !
I tried and this worked for me
Create a model class which has variable of type List<Map<String, String>> myList;
Define a controller similar to below
#PostMapping("/addList")
public ResponseEntity<List<Map<String, String>>> passList(#RequestBody ListModel listModel) {
System.out.println("List mapped " + listModel);
return new ResponseEntity<>(HttpStatus.CREATED);
}
Create a request from Postman or any tool like this
{
"myList": [
{
"one": "1",
"two": "2"
}
]
}
Response I got
List mapped ListModel [myList=[{one=1, two=2}]]
Make sure you map correct variable name ( for e.g. I have defined myList, so that must be passed so it gets properly mapped in Controller class ) also assuming toString, GetterSetters , and your familiarity with few basic REST annotations related to Spring/SpringBoot :)

How can I parse HTTP headers using ktor

I'm using ktor 1.5.3 HTTP client and wondering how can I deserialize HTTP response headers into a list of LinkHeader values. I have the following value in my code:
response.headers.getAll("Link")
which is a list of strings, and I want to get a value of type
List<LinkHeader>
UPDATED:
The details of my use-case:
I have a backend that uses the following response headers to manage pagination:
Link: <https://hostname/v2/issues?orderBy=updated&orderAsc=false&perPage=15>; rel="first"
Link: <https://hostname/v2/issues?orderBy=updated&orderAsc=false&page=2&perPage=15>; rel="prev"
Link: <https://hostname/v2/issues?orderBy=updated&orderAsc=false&page=4&perPage=15>; rel="next"
Link: <https://hostname/v2/issues?orderBy=updated&orderAsc=false&page=116922&perPage=15>; rel="last"
I just have to parse them to understand where is the last page
Since there is not such functionality in Ktor right now, I've created this feature request to address your problem. As a workaround, you can use regular expressions for your particular case to parse headers' values:
data class Link(val url: Url, val rel: String)
fun parse(value: String): Link {
val matches = Regex("""<(.+?)>;\s*rel="(.+?)"""").matchEntire(value) ?: throw Exception("Cannot parse Link header value $value")
val (_, urlString, rel) = (matches.groupValues)
return Link(URLBuilder(urlString).build(), rel)
}
As there is no accurate solution from Ktor, I've implemented a workaround from this article. The same do-while loop worked in my case as well. It makes a redundant API call for an empty last page but works.

Ktor Client, how to specify body parameters

I'm trying to send a POST request to the server, this post requires parameters "email" and "password".
but I don't know how to specify parameters, I read the documentation but I didn't understand.
this is my code:
val request=client.post<String> {
url(BASE_URL+"login.php")
body="email=$email,password=$password"
}
fwiw I use something like following here....though I would have thought specifying url like you do should also work. What issue do you see? The body might also be some json for example, or maybe a data class etc if you have serialization setup.
response = client.post(url) {
body = "some params/data etc"
}
It should work if you use serialization, but I solved my problem by using 'Uploading multipart/form-data'
val request=client.post(url) {
body=MultiPartFormDataContent(formData {
append("email","data")
append("password","data")
})
}
see Documentation

PRISMA: Getting type error on where clause in update method

Have a specific Prisma ORM library error that I need help with.
I have created a migration and pushed it to a postgres db.
I have generated the client model for Prisma and am able to findAll and insert data using the create method.
Where I am having trouble is the update method.
Here's my code
app.post("/articles/:title", async (req: Request, res: Response) => {
const article = await prisma.article.update({
where: { title: req.params.title },
data: { title: req.body.title, content: req.body.content },
})
res.send('The article was posted sucessfully.' + article)
})
I am getting the following error which makes me think that the client is not finding a type 'title' when using the where argument.
app.ts:65:14 - error TS2322: Type '{ title: string; }' is not assignable to type 'ArticleWhereUniqueInput'.
Object literal may only specify known properties, and 'title' does not exist in type 'ArticleWhereUniqueInput'.
65 where: { title: req.params.title },
~~~~~~~~~~~~~~~~~~~~~~~
node_modules/.prisma/client/index.d.ts:784:3
784 where: ArticleWhereUniqueInput
~~~~~
The expected type comes from property 'where' which is declared here on type 'Subset<ArticleUpdateArgs, ArticleUpdateArgs>'
Has anyone else had this issue?
I tried to introspect the database just to make sure the database was captured exactly as is, with title and content fields and then generated the client again.
Many thanks
James
Found the answer: Post answer was a response from Antonie
The fields in
where
needs to be unique.
If you can make some field, let's say date #unique (date: DateTime! #unique), and use that for your where in the upsert, I think it would work (tested on my local).
Use .(find/update/delete)Many() if you are trying to query with multi values.

Feign QueryMap usage with POJO

I've found in FEIGN-README that I can do stuff like:
interface MarketDataRestClient {
#RequestLine("GET /api/v1/depth")
fun getOrderBook(#QueryMap orderBookQuery: OrderBookQuery) : OrderBook
}
OrderBookQuery:
data class OrderBookQuery(val symbol: String, val limit: Int? = 100)
And Feign should generate query params: /api/v1/depth?symbol={symbol}&limit={limit}
Unfortunately all I'm getting is:
Exception in thread "main" java.lang.IllegalStateException: QueryMap parameter must be a Map: class OrderBookQuery
at feign.Util.checkState(Util.java:128)
at feign.Contract$BaseContract.parseAndValidateMetadata(Contract.java:126)
at feign.Contract$BaseContract.parseAndValidatateMetadata(Contract.java:64)
at feign.ReflectiveFeign$ParseHandlersByName.apply(ReflectiveFeign.java:146)
at feign.ReflectiveFeign.newInstance(ReflectiveFeign.java:53)
at feign.Feign$Builder.target(Feign.java:198)
at feign.Feign$Builder.target(Feign.java:194)
This feature will be available in 9.7. The current published version, as of the writing of this answer, is 9.6. If you do not want to wait, please clone the repository and run build the project.
Just add a QueryMapEncoder,like:
return Feign
.builder()
.client(new OkHttpClient())
.logger(new Logger.ErrorLogger()).logLevel(Logger.Level.BASIC)
.queryMapEncoder(new BeanQueryMapEncoder())
.encoder(new GsonEncoder())
.decoder(new GsonDecoder())