Override the path of my API in Springfox Swagger - spring-rest

I am using Spring REST with Springfox Swagger, and I had a method such as
#RequestMapping(method = RequestMethod.POST, value = "/my-methd")
#ApiOperation(value = "My method")
and all was working fine.
Now I notice there is a spelling mistake in the path. I already have clients using the existing API, so I would like to support both the old and new versions, but only have the new versions show up in the documentation.
I can correct it like follows:
#RequestMapping(method = RequestMethod.POST, value = {
"/my-methd", // Spelling mistake, deprecated
"/my-method" // To be used by new software
})
#ApiOperation(value = "My method")
However, both the old and new spelling show up in the Swagger docs.
I want both to work, but only the new spelling to show up in the Swagger docs.
The #ApiOperation has the facility to override the HTTP method, and many other things, but seemingly not the path.
Is there anything I can do here?
(I can't even mark the old method as "deprecated" in the docs, as the docs come from the method annotation, which is shared between the two paths.)

I'd suggest to just create a new separate method, one with the misspelled RequestMapping "/my-methd", and one for the correct one "/my-method".
Then it's easy to mark the misspelled one as deprecated.
Also this way you can put proper comments in the code, so in the future it's easier to maintain / remove.

Related

How to send list as parameter for search in angular service to .net core

Please Help me I need to retrieve a list of details using a list of parameters. How to achieve that from angular 10 and .net Core?
Also, Single Entries is working for search. But If I try to enter a second entry in the input field and tried to search it is not working.
The method name is GetPodForwardings.
This is the Method in angular (Service)
GetPodForwardings(conNo,newPage,pageSize)
{
return this.http.get(`${this.BaseUrl}Pod/GetConsignmentList?conNo=${conNo}&newPage=${newPage}&pageSize=${pageSize}`)
}
In .NET Controller
[Microsoft.AspNetCore.Mvc.Route("GetConsignmentList")]
[HttpGet]
public async Task<IActionResult> GetListofConsignments([FromQuery]List<long> conNo,int currentPage,int pageSize)
{
return await ProcessQuery(new GetListofConsignmentByConsignmentNoQuery(conNo,currentPage,pageSize));
}
The proper way of adding parameters to an url in Angular is to use the second options parameter of the http.get("url",options) function. Unfortunatly they don't accept arrays rightaway (there is an open github issue).
However string interpolation like you did should also work. You seem to just have the wrong format. As this is treated very framework specific look at this answer to get the right format for your case.

How to get rid of route-name conflicts when ensuring api works both with and without the api-version?

I want to apply asp.net api-versioning to my web app (which didn't have versioning). However, the tricky issue is that I must ensure that APIs should work both with and without the api-version.
[ApiVersion("1.0")]
[Route("api/products/{productId}/[controller]")]
[Route("api/v{version:apiVersion}/products/{productId}/[controller]")]
[ValidateModel]
[Produces("application/json")]
public partial class ProductController : ControllerBase {
internal const string GetLatestRoute = "GET Product/GetLatestAsync";
[HttpGet(Name = GetLatestRoute)]
public async Task<IActionResult> GetLatestAsync() {
}
}
I have a controller with multiple actions, each of them is defined with a unique route name. When I add two routes (with and without versions) to the controller, there comes a route-name conflict error:
Attribute routes with the same name 'GET Products/GetLatestAsync' must have the same template:
Action: 'Service.Controllers.ProductController.GetLatestAsync (ProductFD)' - Template: 'api/products/{productId}/Product'
Action: 'Service.Controllers.ProductController.GetLatestAsync (ProductFD)' - Template: 'api/v{version:apiVersion}/products/{productId}/Product'
There are several answers on StackOverflow that say the issue can be solved by removing the route names defined for the action methods. However, in my scenario, the route names are used to create Url Links in several places in the project.
Is there an approach that I can get rid of the issue? I'm wondering whether I could append version to the route name variable or mapping the non-version api to the version/1.0 ...? On the other hand, there is a rare case that I update all the methods in a controller. So is it possible that I only define a route-prefix on the top-level of the controller and only apply the api-version on the method-level?
Route names and the route table are not API version aware. In order for this to work, you need to use double route registration like you have because you are versioning by URL segment (not recommended). If clients are properly following the links returned by the server, then always using the route generated with the explicit version in it will do. If the client doesn't honor that and just calls the APIs directly without the API version, the second template will handle that for you. If you are only generating links with the same controller, then I would suggest using CreatedAtAction instead because it will not rely on the route name. If memory serves me correct, you can specify the order of each [Route] for precedence. If unspecified, it will be the first attribute specified - which matters.
You'll also need to enable:
services.AddApiVersioning(options => options.AssumeDefaultVersionWhenUnspecified = true);
If you haven't already.
Last, but not least, beware the known, breaking change: Async suffix trimmed from controller action names. This has snared many people.

What's the right way to call an action from a different controller in ASP.Net MVC 6

I'm getting a
No route matches the supplied values
while trying to return a RedirectToAction("Action", "Controller"). The method signature says "actionName" and "ControllerName". I'm assuming actionName is the method name in the Controller, Am I correct? For ControllerName I'm using the Controller File Name without the Controller Sufix. Ex.:
return RedirectToAction("Index", "WebApp")
where Index is a method of WebAppController and the command is being issued from a method of AnotherController
Both the caller controller and the called one are on the same Controllers directory on the same application.
I'm cofused because in this ASP.net MVC application there is also Route attributes and Action attributes where you can put names on methods, different than the real method name. In my case I have no Route["Name"] nor [httpXXX("route", Name="dasdasdas")] configured for the methods involved in my attempt.
I have been reading MS docs and some examples but It appears I'm doing the thing right but for strange reasons it's not working. I even tried using Redirect("Controller/Action") and with it the problem vanishes but the new problem is this way of redirect doesn't support passing data parameters to the target route.
At this point I'm not working with Action links in Views, different from Form related ones.
I would really appreciate if at least anyone can give me a hint about where can I find info.
The right way to call an action from a different controller is the one I was using:
return RedirectToAction("AnActionMethodName", "AControllerWithoutControllerSufix"[, object values]);
My problem, after several hour spent was that I added two useMvc calls in the Startup.Configure(...)method:
app.UseMvc();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=MyApp}/{action=Index}/{id?}");
});
This was due to copy + paste of code. It was obviously confusing the MVC component in charge of attending the redirection part, as the right way I supose is tho use only one. (I'm newbie on .Net Platform and its frameworks)
Anyway I leave this as a reminder about the risks and consequences of copying and pasting code. At some point something weird can happen to your app and the cause can be a simple copy + paste error.

Is there a simple way to solve content negotiation in Spring boot

We plan to use content type negitiation as a form of versioning for our rest API but it seems more complex than it should be.
Given the follwing example code :
#RestController
#RequestMapping("/products")
ProductController {
.......
#RequestMapping(value = "/{productID}", method = RequestMethod.GET, produces = "productVersion2/json")
public ResponseEntity<ProductV2> getVersion2(#PathVariable String productID) {
.......
return new ResponseEntity<ProductV2>(product, HttpStatus.OK);
The correct method is being called when test this from e.g postman, but i get a HTTP 406 Not Acceptable as a response. I have been looking several places, but I have not found a a page with a good explanation of what i need to do to make this work.
The response is to be parsed with json just like all other requests, but the response object is modified.
The thought is that we by doing this can support several "versions" of the same API and we can gradually make clients move over to the new api, while still having the same uri/resource to access.
Can anyone point to a good tutirial or a step by step guide of how this can be solved in spring boot ?
I have read this article : http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc/#combined-controller
but I was not able to get a clear anderstanding of what was needed to make it work
Your media type is wrong. To use custom media types for API versioning you could use application/productVersion2+json instead of productVersion2/json. I suspect you get the 406 because Spring Boot has no way to find out how to serialize your object into JSON because productVersion2/json isn't a valid media type for json data.
There is more than one way to pick a media type to do this, I've googled a more comprehensive document here.

Retrofit and usage of absolute URLs

How can you handle in Retrofit absolute URLs for some calls?
I am using a combination of dagger, retrofit and OKHttp. I provide a #Singleton RestAdapter with the selected endpoint (Production, Staging, etc) which it is formed from the BASE URL.
#Provides
#Singleton
RestAdapter providesRestAdapter(Endpoint endpoint,
ObjectMapper jacksonObjectMapper,
Client client,
ApiRequestInterceptor headers) {
return new RestAdapter.Builder() //
.setClient(client) //
.setEndpoint(endpoint) //
.setConverter(new JacksonConverter(jacksonObjectMapper))
.setLogLevel(RestAdapter.LogLevel.FULL)
.setRequestInterceptor(headers) //
.build();
}
The problem is that the REST service, for some cases, returns the URL for the content to be loaded in ABSOLUTE format meaning something like http://someurl.com/resource?sort=ascendent and not the preferable /resouce?sort=ascendent (without the BASE_URL)
Now the question is how I can create the interface of the service to deal with such scenario?
I was thinking something like:
public interface PlaceholdersService {
#GET("{placeholderHref}")
public void getPlaceholder(#EncodedPath("placeholderHref") String placeholderHref);
}
The problem is that I am not sure if the BASE URL set in the Endpoint previously when creating the RestAdapter will be added (can't test it at the moment).
Another though was to create a new RestAdapter specially for this case with an Endpoint set to a null or empty string fixed point like Endpoints.newFixedEndpoint(null) or Endpoints.newFixedEndpoint("").
Any suggestions?
Thanks
Digging a little bit I just realised there is an open issue for this manner in Github https://github.com/square/retrofit/issues/333
It has been moved the discussion to the V2 of the library to discuss if will be supported or not in that version.
This means that if supported, won't do it for a while. Is there any suggestion or workaround you can suggest to surpass this issue for the moment?
I had a similar problem and I solved it by creating new adapter with specified URL and use an empty path in my interface. Here is my question and my own answer.
Hope it helps.

Resources