.Net Core 5: WebApi query string parameters - asp.net-web-api

Is it possible to Swagger a Get Api with one parameter that can be different in name?
I Explain, I should create a controller that can have this behaviour:
GET <MySite>/suppliers?srm=0016018132
GET <MySite>/suppliers?vat=02123420040
srm and vat are mutually exclusive. A user can call one of two form of the api.

short answer
no
a little longer answer
where in c# a method's "uniqueness" derives from the name and parameter order/type, in a web api only a method's name determines "uniqueness".

Related

Best practice of creation GET methods with many parameters(filters)

I have the GET method in my Spring REST controller. This method returns the list of users by the filter.
I have a few ways to implement it:
Add #PathVariable like - /users/{type}/{age}/{name}/...(bad approach in this case)
Add #RequestParam like - /users?type=type,age=age,name=name...(usual approach in this case)
Use RequestDto (the best approach) like
public class UsersRequestDto {
private String type;
private int age;
private String name;
...
}
But I can not use GET method for this. I must use POST method with #RequestBody
And it breaks the rules. My method doesn't change state and doesn't create any entities. It workes as the GET method but in reality, it is POST.
And I have 2 ways:
Use the GET method with many parameters
Use the POST method with DTO which works as the GET method and confuses users.
Which way is better?
Short version: you might be looking for How to bind #RequestParam to object in Spring. (See also: https://stackoverflow.com/a/16942352/54734 )
On the web, we would have an html form with a GET action. When the form is submitted, the browser would process the input controls and create the application/x-www-form-urlencoded representation of the form data. For a GET action, that representation is used as the query string.
Using GET, and encoding all of the information into the query string, allows us to take advantage of general purpose caching of the results.
But the query parameters aren't accessible by themselves - they are actually embedded within the larger context of the HTTP request. We don't usually see that because, once again, general purpose components can do a lot of the heavy lifting.
So we don't see the parser that extracts the target-uri from the request, or the parser that splits the target URI into its separate components, or the parser that splits the query part into a sequence of key value pairs....
In general, what we do is ride the "general purpose" implementation as far as we can, then get off and do the rest of the work ourselves. If the framework offered no better support for object mapping, that could mean implementing that mapping ourselves.
So if our framework lacked the capability to map the query string directly to an object representation, we would hand roll that part of the implementation ourselves (either by copying each parameter "by hand", or writing our own reflection code to do the mapping automagically).
But it seems that Spring has that capability already built into it; and that it is the default option (no annotation required); you just have to be sure that the object implementation provides the interface that Spring needs to execute the mapping.
How many different parameters are you including in your query?
Personally, I prefer the option of a GET method with many different parameters. It has other benefits such as being cacheable as well. Also, compare it to something like a the URL that a Google search generates - lots of query string parameters.
The POST option feels dirty - it's a violation of what a POST should actually do (creating or updating a resource).
See these discussions: https://softwareengineering.stackexchange.com/questions/233164/how-do-searches-fit-into-a-restful-interface and REST API Best practices: Where to put parameters?
1st of all when you are using RequestParam then key will be added with & symbol not with comma(,) .
when you want to filter ( as you have mentioned) something then best approach would be to use RequestParam.
To minimize the code you can opt to "MultiValueMap" or "HttpservletRequest" .
1)HttpServletRequest
#GetMapping("/user")
public List<User> getFilteredUser(HttpServletRequest httpservlet)
httpservlet.getQuesryString() //will return all request param.
2)MultiValueMap
#RequestParam MultiValueMap<String,String> params
NOTE:- Generally POST is for create/update record.

Api Platform - returning data from external API

I'm currently using API Platform to display some data in Elasticsearch. This works fine, but I now have another feature that I'm looking at.
My application needs to deal with a 3rd-party API that needs to hit an endpoint and return some data.
Within my app, I'd like to be able to hit (/api/logistics/{action} - where action is an endpoint, such as login) and this then hits my app layer and returns data (3rd-party can be re-named)
The API calls to the 3rd party are fine, but I'm unsure how to display the response.
I've seen https://api-platform.com/docs/core/data-providers/ which looks like i can create a custom response.
Do i still need to create an entity/model and configure the #ApiResource() with a controller that uses my Data Provider?
If so, then what do i need to add in my annotation, since I won't have an id identifier
I'm fairly new to API Platform and I've not used the Data Provider functionality before
I will not be storing the data from the 3rd party API, just doing a HTTP call, retrieving the response and hopefully displaying it via Api Platform
Thanks
You are mosly right about the dataprovider. But as the docs page General Design Considerations states, "you have to write a plain old PHP object (POPO) representing the input and output of your endpoint. This is the class that is marked with the #ApiResource annotation. This class doesn't have to be mapped with Doctrine ORM, or any other persistence system."
So no, it does not need to be an Entity, but there must be a class marked with the #ApiResource annotation (but putting it in the Entity folder may help to make the #ApiResource() tag work - or adding the folder of your class in api/config/packages/api_platform.yaml).
For an item "get" endpoint your POPO needs an id. The poperty - or if there is only a getter, the getter - must be marked with the #ApiProperty(identifier=true) tag. Usually the easiest way to make one is by imploding/encoding some strings from the response of the external api call that together are unique for the response and will not change. Your dataprovider will have to explode/decode the id and use the components to make the external api call.
For a "post" operation you need a datapersister instead of a dataprovider. Apip will instatiate and populate your POPO and pass it to the datapersister and from there you can make the call to the external api and return an object as the result. If your object is not the same type of POPO you should specify "output"=TheOutputClass::class or put the operation on the output class and specify "input"=TheInputClass::class (replace TheOutputClass or TheInputClass by the actual class name)
For "put" and "patch" you need both a dataprovider, a datapersister and an id. They can have different input and output classes, see the docs about DTOs.
A collectionoperations with method "get" may seem convenient because you can just pass it any query string but your CollectionDataProvider must return an iterable.

Spring Data Rest: pass Collection<Entity> as query String parameter

First off, this is related to Spring Data Rest: How to search by another object's key? which appears to be resolved in https://jira.spring.io/browse/DATAREST-502
My issue is (I believe) and extension of this. I'm seeing the following behavior:
I have two repository queries defined e.g.
Person findByAccount(#Param("account") Account account));
Collection<Person> findByAccountIn(#Param("accounts") Collection<Account> accounts));
Both search methods are exposed via spring-data-rest. I can access the first using a url such as http://localhost:8080/people/search/findByAccount?account=http://localhost:8080/accounts/1
I can access the second method using a url such as http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1, but if I try to pass in MULTIPLE accounts, such as
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1,http://localhost:8080/accounts/2,
It will run the query except will IGNORE the first account (http://localhost:8080/accounts/1) and only search based on the second (http://localhost:8080/accounts/2)
What is the proper technique for passing in a Collection of entities to a repository argument over the REST API? I find it works great for a single entity, but not for a Collection. Note that both of these repository methods are working as expected when directly accessing the JpaRepository.
Also note that these queries seem to work if the collection is of some primitive type, for example findByAccountIdIn(#Param("accountIds") Collection<Long> accountIds) is accessible with intended functionality via http://localhost:8080/people/search/findByAccountIdIn?accountIds=1,2. This leads me to believe it's possibly an error in the way a list of URIs is passed into a query method which expects a Collection of corresponding entities.
Thanks in advance for any help!
Try repeat the query parameter as most servers will interpret this as a list. It might not be the prettiest solution but should work.
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1&accounts=http://localhost:8080/accounts/2
I know that this is forever old, but I found the answer.
I will put this here for anyone else who should wander this way:
How to use List in endpoint exported by Spring Data REST?
List<Person> findByAccountIn(#Param("accounts") Account... accounts);
the request would look like this:
http://localhost:8080/people/search/findByAccountIn?accounts=http://localhost:8080/accounts/1&accounts=http://localhost:8080/accounts/2&accounts=http://localhost/accounts/anotheraccountid

MVC How to pass a model beetwen two different applications

Here is the thing! At the company where I work there are two applications builted in MVC, one of these is used for loguin and some special funtionalities and the other one is used for global user's (I don't realy know why there are two applications. I think it most be just one).
Well, that is the context, now what I need to do is to pass a model from one application to the other, the problem is that I need to do it in the Action method to another Action method. The only method I found to do it is Redirect() but it only receive an url string and I can't pass query string's.
Is there a way to pass an encrypted model(I'm not sure if encrypted is the right word, but I think you know what I mean)?

Attribute Routing vs Convention

Playing around with the Web.API 2.0 stuff- in particular Attribute Routing. The docs state that you can have attribute routing AND the 1.0 routing by convention... but these two don't seem to play that well together. For example, given these two methods:
public override HttpResponseMessage PutModel(SampleForm form)
[HttpPut("approvesampleform/{form}")]
public string ApproveSampleForm([FromBody]SampleForm form)
While I can call http://localhost/api/sampleform/approvesampleform just fine, a PUT to http://localhost/api/sampleform/ generates a Multiple actions were found that match the request error.
Is there any way that if a method is marked with the attribute routing it is ignored by the convention? This would be ideal... but I don't see any way to accomplish this in the docs.
Note: I don't see a asp.net-web-api-2 tag. Perhaps someone with more than 1500 rep can create it?
Right, RC (Release Candidate) did not have the logic where conventional routes cannot access attributed controller/actions. This change came post-RC. The scenario you are trying would work fine in post-RC bits.
Probably the docs you mentioned aren't very clear, but I think they mean that you could have attributed and convention based controllers work side-by-side and not particularly about mixing both attributed and conventional semantics in the same controller.
For time being you could probably use only attribute routing for your controller mentioned above.

Resources