Communicating acceptable string values in Swagger docs - spring

Spring Boot (Java) here. Does Swagger have any customizable/configurable fields that allows you to specify specific String values that an endpoint either accepts or returns?
For instance I might have an endpoint like so:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
]
}
...that accepts an array of notificationTypes in its request entity. Perhaps my server only allows AdminNotification and SimpleAlert as the possible values for this notificationTypes, meaning:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
"SimpleAlert"
]
}
is valid but:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
"Hello"
]
}
throws a 400 Bad Request. I'd like to be able to communicate this in my Swagger docs. Is this configuration possible via annotations?

I think a good solution would be to create an ENUM with the accepted values. This way, it will be automatically described in Swagger:
#ApiModelProperty(value= "Accepted values are :")
public NotificationTypes notificationTypes;
public enum NotificationTypes {SimpleAlerts, AdminNotifications}
In the generated specifications, it gives the following:
Have fun !

You can use something like -
notificationTypes:
type: string
example: ["SimpleAlert", "otherValue"]
look - https://gyazo.com/1c8774fbf08410c19df0506a52a767d6
ref - https://swagger.io/docs/specification/adding-examples/

Related

Can I transform the input of a json inside a spring boot controller?

I have a very simple spring boot web application which consumes requests with json body.
For each json which the application will receive (from any client) I would like to manipulate it as a first step.
For example if the client sends the following body:
{
"hello": "world!!!"
}
I would like to replace each ! with a ?. In this case the result is:
{
"hello": "world???"
}
This json transformation should be valid for each controller and for any json entering the system.
Is this kind of operation possible?
Thanks.
You may use string.replace to do the same.
Or also you can add custom annotation to manipulate the values of any keys.
You can use any replacement methods or regex in your classes.
#GetMapping
public String replace(RequestItem item){
// item = item.regex/replacement method
// call your service or whatever
return item;
}
When you got the data, you can do whatever you want to do.

Usage of search parameter "_profile" in HAPI FHIR

In the FHIR REST API, there are some standard parameters for all resources that can be used in the 'search' endpoints.
I need to use the '_profile' parameter on a search operation: https://www.hl7.org/fhir/search.html#profile
The HAPI FHIR documentation on implementing search operations (https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations_search.html) has a lot of examples, none mention the parameters that apply to all the resources, like '_profile'.
I also checked their test server online (http://hapi.fhir.org/resource?serverId=home_r4&pretty=true&resource=Observation) and I can't find a way to specify the '_profile' there, to see how it works.
At the code level, what I'm trying to do is this:
#Search
public List<Observation> getObservationsByProfile(??? profile)
{
...
if (profile == '...')
{
...
}
else
{
...
}
...
}
I don't know how to specify the annotations and type of the parameter so it binds to the value provided in the '_profile' param un the requested URL.
Is there any sample code or documentation I can refere to? Thanks.
The way to make the search work with the "_profile" parameters is this:
#Search
public List<Observation> getObservationsByProfile(#OptionalParam(name="_profile) UriParam profile)
{
...
if (profile == '...')
{
...
}
else
{
...
}
...
}
Even though the _xxx parameters apply to all the FHIR resources, the HAPI FHIR documentation doesn't include an example on how to use those in the search. Hope this helps as reference for others.

Feign get request with body

For some reason I need to call a GET method API and pass json request body for it. I really couldn't find an example for it. I wonder if it is even supported using feign.
How can I do that using feign?
Yes, Feign supports it. You can do the same as with POST requests:
#FeignClient(name = "clientName", url = "http://localhost:8888")
public interface SampleFeignClient {
#GetMapping("/remote")
String test(#RequestBody SampleRequestBody sampleRequestBody);
}
But be aware: a lot of servers ignore body or even refuse that kind of "non-standard" requests completely (GET or HEAD with request bodies).
According to the documentation the correct way to do it would be to use the #SpringQueryMap annotation.
#FeignClient(name = "clientName", url = "http://localhost:8888")
public interface SampleFeignClient {
#GetMapping("/remote")
String test(#SpringQueryMap SampleRequestBody sampleRequestBody);
}
You can find more information here

How to just get the data using CRUD POST method?

I have developed Small Spring boot Rest api app. I can able to get the data or create new record and search with paging and sorting.
Now i'm looking for provide input data in body to get the data instead of providing in URL with GET method. Is this method also default function ? Please advise.
public interface CodeTextRepository extends PagingAndSortingRepository<CodeText, Long> {
}
How to write POST method to just get the data ?
http://localhost:8080/api/code
method : POST
{
"code":1
}
If I understand you correctly, you want to create a controller that will get the a model as body parameter ({ "code": 1 }) in a POST method and then do something with it.
To do that, you can create a controller that looks like the following (I inserted pseudo-code as an example):
#RestController
#RequestMapping(value = "/api/code")
public class CodeTextController {
private CodeTextRepository codeTextRepository;
// constructor injection
public CodeTextController(CodeTextRepository codeTextRepository) {
this.codeTextRepository = codeTextRepository;
}
#PostMapping
public CodeText postCodeText(#RequestBody CodeTextRequest codeTextRequest) {
// some code to get from the DB
return codeText;
}
}
public class CodeTextRequest {
private int code;
// getters and setters
}
Simply add Accept header to the request, like
accept: application/json
Spring Data-Rest will return the body after a POST request if either the returnBodyOnCreate flag was explicitly set to true in the RepositoryRestConfiguration OR if the flag was NOT set AND the request has an Accept header.
You can set the flag directly during configuration, or you can set it via the application.properties:
spring.data.rest.returnBodyOnCreate = true
you can also set it separately for update:
spring.data.rest.returnBodyOnUpdate = true
---- edit
Maybe I misunderstood your question. If you simply want to GET an existing data using POST method, then DO NOT DO IT AT ALL! That's not a REST API any more. There must be some reason you want to do it, but you should try do resolve that original problem instead in another way!

How to get Swagger UI to display similar Spring Boot REST endpoints?

I have a controller class with two endpoints
#RestController
#RequestMapping
public class TestController {
#RequestMapping(
value= "/test",
method = RequestMethod.GET)
#ResponseBody
public String getTest() {
return "test without params";
}
#RequestMapping(
value= "/test",
params = {"param"},
method = RequestMethod.GET)
#ResponseBody
public String getTest(#PathParam("param") int param) {
return "test with param";
}
}
One has a parameter, one doesn't, and the both work.
If I use curl or a web browser to hit the endpoints
http://localhost:8081/test
returns
test without params
and
http://localhost:8081/test?param=1
returns
test with param
but the swagger ui only shows the one without a parameter.
If I change the value in the request mapping for the request with a parameter to
#RequestMapping(
value= "/testbyparam",
params = {"param"},
method = RequestMethod.GET)
Swagger UI displays both endpoints correctly, but I'd rather not define my endpoints based on what swagger will or won't display.
Is there any way for me to get swagger ui to properly display endpoints with matching values, but different parameters?
Edit for Clarification:
The endpoints work perfectly fine; /test and /test?param=1 both work perfectly, the issue is that swagger-ui won't display them.
I would like for swagger ui to display the endpoints I have defined, but if it can't, then I'll just have to live with swagger-ui missing some of my endpoints.
Edit with reference:
The people answering here: Proper REST formatted URL with date ranges
explicitly say not to seperate the query string with a slash
They also said "There shouldn't be a slash before the query string."
The issue is in your Request Mapping, The second method declaration is overriding the first method. As Resource Mapping value is same.
Try changing the second method to below. As you want to give input in QueryParam rather than path variable, you should use #RequestParam not #PathParam.
Note that you have to give /test/, In order to tell Spring that your mapping is not ambiguous. Hope it helps.
#RequestMapping(
value= "/test/",
method = RequestMethod.GET)
#ResponseBody
public String getTest (#RequestParam("param") int param) {
return "test with param"+param;
}
Upon reading clarifications, the issue here is that swagger-ui is doing the correct thing.
You have two controller endpoints, but they are for the same RESOURCE /test that takes a set of optional query parameters.
Effectively, all mapped controller endpoints that have the same method (GET) and request mapping (/test) represent a single logical resource. GET operation on the test resource, and a set of optional parameters which may affect the results of invoking that operation.
The fact that you've implemented this as two separate controller endpoints is an implementation detail and does not change the fact that there is a single /test resource that can be operated upon.
What would be the benefit to consumers of your API by listing this as two separate endpoints in swagger UI vs a single endpoint with optional parameters? Perhaps it could constrain the set of allowed valid query parameters (if you set ?foo you MUST set &bar) but this can also be done in descriptive text, and is a much more standard approach. Personally, I am unfamiliar with any publicly documented api that distinguishes multiple operations for the same resource differentiated by query params.
As per Open API Specification 3
OpenAPI defines a unique operation as a combination of a path and an
HTTP method. This means that two GET or two POST methods for the same
path are not allowed – even if they have different parameters
(parameters have no effect on uniqueness).
Reference - https://swagger.io/docs/specification/paths-and-operations/
This was also raised as an issue but it was closed because OAS3 doesn't allow that -
https://github.com/springdoc/springdoc-openapi/issues/859
Try including the param in the path as below.
#GetMapping("/test/{param}")
public String getTest(#PathVariable final int param) {
return "test with param";
}
I'm unclear exactly what you're attempting to do, but I'll give two solutions:
If you want to have PATH parameters e.g. GET /test & GET /test/123 you can do:
#GetMapping("/test")
public String getTest() {
return "test without params";
}
#GetMapping("test/{param}")
public String getTest(#PathVariable("param") int param) {
return "test with param";
}
If you want query parameters (GET /test and GET /test?param=123) then you need a single endpoint that takes an optional parameter:
#GetMapping("test")
public String getTest(#RequestParam("param") Integer param) {
if(param == null) {
return "test without params";
} else {
return "test with param";
}
}

Resources