Getting 415 Unsupported Media Type when trying to send request body in text/plain - spring

I have an API which accepts both json and text as request body.
#Path("submitObjects")
#Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
#Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
public List<APIResult> submitMultiObjects(#DefaultValue("false") #QueryParam(("suppressWarnings"))Boolean suppressWarnings,List<MyObject> objects) {
// API logic
}
class MyObject{
private String name;
private String description;
// and getters and setters
}
When I hit the API with request body in JSON it works fine.
[{
"name": "name1",
"description": "description1"
},{
"name": "name2",
"description": "description2"
}]
success for above request body
But when I pass request body in plain text it fails with error code 415 - Unsupported media type
name=name1
description=description1
failed for above request body
name=name1
description=description1
name=name2
description=description2
failed for above request body
I wanted to know how we can pass list of objects in plain/ text format.
For below API where I am using MyObject instead of List
#Path("submitObject")
#Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
#Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
public List<APIResult> submitObject(#DefaultValue("false") #QueryParam(("suppressWarnings"))Boolean suppressWarnings,MyObject object) {
// API logic
}
name=name1
description=description1
above request body works fine.

Related

No value in FHIR extensions

I have a C# REST API that uses the Hl7.Fhir.R4 library (3.7.0) with a POST method that receives an object of type Hl7.Fhir.Model.Patient:
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[HttpPost()]
public async Task<IActionResult> Post(Patient patient)
{
IActionResult status = NotFound();
...
}
The Patient object has a list of extensions:
"extension": [
{
"url": "http://example.com/fhir/extension/patient/origin",
"valueString": "test"
},
{
"url": "http://example.com/fhir/extension/patient/domainId",
"valueInt" : "10"
}...
When receiving the JSON as a parameter in the POST function, all the fields have a better value than those of type 'Hl7.Fhir.Model.DataType':
Extension[0]
Children: {Hl7.Fhir.Model.Extension.<get_Children>d__17}
ElementId: null
NamedChildren: {Hl7.Fhir.Model.Extension.<get_NamedChildren>d__19}
Extension: Count = 0
TypeName: "Extension"
Url: "http://example.com/fhir/extension/patient/origin"
Value: null
Am I missing some decorator or attribute or simply can't the object be directly deserialized?
Did you use the FhirJsonParser from the library to parse the data? You cannot use a regular JSON parser, because it will not be able to handle the FHIR model correctly.
ETA:
As you now mention in your question, the object cannot be directly deserialized, see first part of my response.
Maybe you can take a look at this project to see how it's done there: https://github.com/brianpos/fhir-net-web-api

Youtube Data API with Kotlin: The request is missing a valid API key

So I'm trying to use the Youtube Data API with Kotlin + Spring Boot and I've been struggling a bit.
For now, I'm using hardcoded values for the api_key and the access_token for test purposes.
I'm trying to send a request to list my playlists but I keep getting this error:
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"errors": [
{
"message": "The request is missing a valid API key.",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
Here's my code:
Controller:
#RestController
class PlaylistController(
private val youtubeService: YoutubeService
) {
#GetMapping("/playlists")
fun getPlaylists() : YoutubePlaylistResponse {
return youtubeService.getPlaylists()
}
}
Service:
#Service
class YoutubeService(
private val youtubeClient: YoutubeClient
) {
fun getPlaylists() = youtubeClient.getPlaylists(
access_token = "[ACCESS_TOKEN]",
api_key = "[API_KEY]"
)
}
Client
#FeignClient(name = "youtube", url = "https://www.googleapis.com/youtube/v3")
interface YoutubeClient {
#GetMapping("/playlists")
fun getPlaylists(
#RequestHeader("Authorization", required = true) access_token: String,
#RequestParam("api_key") api_key: String,
#RequestParam("part") part: String = "snippet",
#RequestParam("mine") mine: Boolean = true
): YoutubePlaylistResponse
}
Any thoughts on what I'm doing wrong?
PS: I'm getting the acess_token through the OAuth 2.0 Playground
Edit:
I was calling api_key but it's actually only key.
But now I'm getting a new problem:
"error": {
"code": 401,
"message": "The request uses the \u003ccode\u003emine\u003c/code\u003e parameter but is not properly authorized.",
"errors": [
{
"message": "The r... (464 bytes)]] with root cause
Apparently, it's because I'm trying to access my playlists and it says that I don't have the permission, but when I do the same request using cURL I get an appropriate response. Any thoughts on this?
According to the API documentation, the parameter should be called key rather than api_key:
Every request must either specify an API key (with the key parameter) or provide an OAuth 2.0 token. Your API key is available in the Developer Console's API Access pane for your project.
Source: https://developers.google.com/youtube/v3/docs

Capturing ONLY sent fields in the Request body in Spring Boot PATCH rest API

I am trying to implement a PATCH API as follows:
#PatchMapping("/student)
public ResponseEntity<StudentDTO> patchStudent(#RequestBody StudentDTO studentDTO)
throws URISyntaxException {
...
}
Here StudentDTO is as follows:
class StudentDTO {
String name,
String rollNum,
String grade,
String id,
...
}
Here in PATCH API, user may send any number of fields including id as follows:
Request 1:
{
id: 1,
name: "Test"
}
Request 2:
{
id:1,
name: "Test",
rollNumber : "123456"
}
Request 3:
{
id:1,
name: "Test",
rollNumber : "123456",
grade : null. //NOTE: user may send null as well for a field in request body
}
I a not getting how should I capture only those fields in the request body while patching the data in the backend?

How I can return my custom json file instead of default json file that generates spring boot?

I have a rest controller for authorization:
#RestController
class AuthController {
#PostMapping("/sign-up")
fun signUp(#RequestBody signUpRequest: SignUpRequest): ResponseEntity<String> {
some code here..
}
}
The signUp method gets SignUpRequest model as a request body. SignUpRequest model is:
enum class Role {
#JsonProperty("Student")
STUDENT,
#JsonProperty("Tutor")
TUTOR
}
data class SignUpRequest(
val role: Role,
val email: String,
val password: String
)
When I make /sign-up post request with JSON:
{
"role": "asdf",
"email": "",
"password": ""
}
It returns me an answer that were generated by spring boot:
{
"timestamp": "2020-02-12T05:45:42.387+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]\n at [Source: (PushbackInputStream); line: 3, column: 10] (through reference chain: foo.bar.xyz.model.SignUpRequest[\"role\"])",
"path": "/sign-up"
}
Question is: How I can return my custom JSON instead of that default generated JSON?
I want to return my custom JSON, like:
{
"result": "Invalid user data are given",
"errors": [
{
"fieldName": "ROLE",
"text": "Given role does not exist"
},
{
"fieldName": "EMAIL",
"text": "EMAIL is empty"
}
]
}
I suggest you to create ErrorContrller that generates custom json map as response. Then when you will catch an error in sign-up method, call ErrorContrllers method.
You can find info from this link
Finally I found out a solution. You should create a class that annotates #ControllerAdvice, and make a method that annotates #ExceptionHandler.
#ControllerAdvice
class HttpMessageNotReadableExceptionController {
#ExceptionHandler(HttpMessageNotReadableException::class)
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
fun handleException(
exception: HttpMessageNotReadableException
): PostSignUpResponseError {
val errors = mutableListOf<PostSignUpResponseErrorItem>()
errors.add(
PostSignUpResponseErrorItem(
fieldNamePost = "Role",
text = "Given role does not exist"
)
)
return PostSignUpResponseError(
result = "Invalid user data are given",
errors = errors
)
}
}
where PostSignUpResponseErrorItem and PostSignUpResponseError are:
data class PostSignUpResponseError(
val result: String,
val errors: List<PostSignUpResponseErrorItem>
)
class PostSignUpResponseErrorItem(
val fieldNamePost: PostSignUpRequestFieldName,
val text: String
)
Anyway, I still don't know how to attach this thing to a certain PostMapping method.

WebApi 2.1 Model validation works locally, but does not show missing fields when run on the server

We are using WebApi v2.1 and validating ModelState via a filter applied in the WebApiConfig class.
Fields specified as required are not listed on the error message when we run on the server (Win Server 2008R2), but they work perfectly when we run locally (on IISExpress).
The request is correctly rejected locally and on the server, but the server response does not show the missing fields.
For Example:
Given a Local request that lacks the required abbreviation and issuerName fields, the response shows as expected:
{
"message": "The request is invalid.",
"modelState": {
"value": [
"Required property 'abbreviation' not found in JSON. Path '', line 18, position 2.",
"Required property 'issuerName' not found in JSON. Path '', line 18, position 2."
]
}
When the same request is sent to the server, the response shows:
{
"message": "The request is invalid.",
"modelState": {
"value": [
"An error has occurred.",
"An error has occurred."
]
}
}
Our filter is the following:
public class ValidateModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
Our data model class is decorated with the DataContract attribute, and the required fields are attributed like so:
[DataMember(IsRequired=true)]
public string IssuerName
The server is more restrictive about sending errors down ot the client. Try setting the IncludeErrorDetails flag on your httpconfiguration to verify that this is the underlying issue.
In general though turning this flag on is not the best idea, and you will want to serialize the errors down differently.
For more info:
http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx

Resources