Swagger Codegen IO: Change Service Naming Convention and Nickname - c#

Is there anyway to override Swagger IO CodeGen naming conventions, when its creating Angular API Service Proxies?
https://editor.swagger.io/
Its naming by this equation: API + Controller Name + Controller Method + HTTP Action.
public apiProductGetProductByProductIdGet(productNumber?: string, observe?: 'body', reportProgress?: boolean): Observable<ProductResponse>;
We want to restructure/reorder the naming convention for our company.
Currently linking Net Core 3 APIs with Angular Typescript.
Will accept javascript answer for CodeGen.
Update Possible Solution:
How do I change the nickname property in C#?
https://docs.swagger.io/spec.html
"Nickname. A unique id for the operation that can be used by tools reading the output for further and easier manipulation. For example, Swagger-Codegen will use the nickname as the method name of the operation in the client it generates. The value MUST be alphanumeric and may include underscores. Whitespace characters are not allowed.
"nickname": "addPet",

You are looking for the operationId property:
operationId is an optional unique string used to identify an
operation. If provided, these IDs must be unique among all operations
described in your API.
https://swagger.io/docs/specification/paths-and-operations/
Example:
/users:
get:
operationId: getUsers
summary: Gets all users
...
post:
operationId: addUser
summary: Adds a new user
...
/user/{id}:
get:
operationId: getUserById
summary: Gets a user by user ID
...
If you're using Swashbuckle, you can specify the operationId a couple of different ways below:
[HttpGet("{id:int}", Name = nameof(GetProductById))]
public IActionResult GetProductById(int id) // operationId = "GetProductById"'
or
[HttpGet("{id:int}", Name = "GetProductById")]
public IActionResult GetProductById(int id) // operationId = "GetProductById"'
See this also

You can also change the generated client SDK service naming conventions using tags (if you're like me and want to prevent conflict with client services).
Instead of tagging as user, and having the client SDK generate the service name as UserService, you can use the tag of user-api and the generated library service will be named UserApiService.
https://swagger.io/docs/specification/2-0/grouping-operations-with-tags/

Related

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints

I have an ASP.Net Core WebAPI, I got below requirement as
I have 2 methods to handle HTTP GET requests, the first one for GetCustomer by id(string) and the other one to GetCustomer by email(string).
//GET : api/customers/2913a1ad-d990-412a-8e30-dbe464c2a85e
[HttpGet("{id}")]
public async Task<ActionResult<Customer>> GetCustomer([FromRoute]string id)
{
}
// GET: api/customers/myemail#gmail.com
[HttpGet("{name}")]
public async Task<ActionResult<Customer>> GetCustomerByEmail([FromRoute]string email)
{
}
when I try to this Endpoint, I get exception as:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.
Which is quite Obivious & understood.
It could be easily addressed by appending/prepending some string in the route like
/api/customer/{id}
/api/customer/emai/{id}
However not so convinced with this apporach however on googling I get the below SO link
How to handle multiple endpoints in ASP.Net Core 3 Web API properly
But this guy has one parameter as int while the other as string so route constraint rescued.
however, I see some people posting/suggesting on the same post to add [Route("")] but I didn't get how this attribute is useful ?
afaik, Route("") and HTTPGet("") //any HttpVerb serves the same purpose?
Anyways how could I handle my requirement elegantly?
You can add route constraints to disambiguate between the two routes:
[HttpGet("{id:guid}")]
[HttpGet("{name}")]
You could also create your own email constraint or use regex(.) constraint for the email parameter.

OData controller method with multiple parameters

I need to create an OData controller with this assign.
http://xxxxxx/odata/mock/Itens(NumContrato='1234',IdItem='10')/Pedidos
ItensController
public class ItensController : ODataController
{
[HttpPost]
[ODataRoute("(NumContrato={NumContrato},IdItem={IdItem})/Pedidos")]
public IQueryable<Pedido> Pedidos([FromODataUri] string NumContrato, [FromODataUri] string IdItem)
{
... do something
}
}
WebApiConfig.cs
...
config.Routes.MapODataServiceRoute(
"ODataRoute",
"odata/mock",
model: GetModel(),
new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
...
public static IEdmModel GetModel()
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
...
builder.EntitySet<Dominio.ODataSapFake.Item>("Itens");
builder.EntitySet<Dominio.ODataSapFake.LinhaDeServico>("LinhasDeServicos");
builder.EntitySet<Dominio.ODataSapFake.Pedido>("Pedidos");
var a = builder.Entity<Dominio.ODataSapFake.Item>().Collection.Action("Pedidos");
a.Parameter<string>("NumContrato");
a.Parameter<string>("IdItem");
a.ReturnsCollectionFromEntitySet<Dominio.ODataSapFake.Pedido>("Pedidos");
...
return builder.GetEdmModel();
}
An error occurs when call service.
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code/>
<m:message xml:lang="en-US">
No HTTP resource was found that matches the request URI 'http://localhost:4492/odata/mock/Itens(NumContrato='100',IdItem='00040')/Pedidos'.
</m:message>
<m:innererror>
<m:message>No routing convention was found to select an action for the OData path with template '~/entityset/key/navigation'.
</m:message>
<m:type/>
<m:stacktrace/>
</m:innererror>
</m:error>
Either your URL is incorrect, or your configuration is incorrect, lets explore both possibilities:
Assuming that the config is correct, you have declared Action called Pedidos has 2 parameters, and it is bound to the collection, no to an item... the URL that matches your definition is actually:
~/Itens/Pedidos(NumContrato='1234',IdItem='10')
Assuming that URL is correct, then you need to configure the endpoint as an Item bound Action and we also assume that the Itens record already has the keys NumContrato and IdItem defined:
builder.EntitySet<Dominio.ODataSapFake.LinhaDeServico>("LinhasDeServicos");
builder.EntitySet<Dominio.ODataSapFake.Pedido>("Pedidos");
var itens = builder.EntitySet<Dominio.ODataSapFake.Item>("Itens");
// Key should be defined by attribute notation, but we can redefine it here for clarity
itens.EntityType.HasKey(x => x.NumContrato);
itens.EntityType.HasKey(x => x.IdItem);
// declare the Action bound to an Item
itens.Item.Action("Pedidos")
.ReturnsCollectionFromEntitySet<Dominio.ODataSapFake.Pedido>("Pedidos");
Update 1 - GET support:
Action supports HTTP Post, which OP has decorated the method with, but if you intend to support HTTP GET, then you must configure the endpoint as a Function instead. The syntax is still the same.
don't forget to remove the [HttpPost] attribute, consider replacing it with [EnableQuery] or [HttpGet]
Update 2 - Item Navigation with Composite Key
If the Item data record has a Navigation Property called Pedidos and your intention is to support the standard Item navigation down this property path then you do not need to include this information in the config all.
remove the [HttpPost], this is a GET request.
remove the [ODataRoute] attribute, the default routes should work
Make sure that you use the names of the key properties, using the same casing and order as they are declared with in the configuration.
If you are using auto configuration, then the order will match the Key attribute column specification in your data model.
For OData v3 you may need to follow this advice: Odata v3 Web Api navigation with composite key

How can I specify when creating a web request that I want to receive certain fields from [FromBody]

I am creating a web service for user authentication. (I am new in c# using entity framework core)
[HttpPost, Route("login")]
public async Task<ActionResult<Usuario>> Login([FromBody] User user)
{
}
my model User has the next fields:
{
name,
password,
phone,
email
}
I don't know how to specify so that from the client side, my users can see the fields that my web service needs to receive and when I use some plugin to document my API it can be clearly seen that I ONLY need the name to be sent and password only.
I think of something like that, I hope to make myself understand:
public async Task<ActionResult<Usuario>> Login([FromBody] string email, [FromBody] string password)
so in this way when the API is documented, I would like it to be understood that you need to send email and password only
and so from the client side
{"password": "212346", "email": "myemail#hotmail.com" }
is sent
Your view model should contain ONLY the fields each API method requires. If there are fields in your request that are not required, they should not be in the method body. If you use something like Swagger to document your API, then it will show just the fields required for each method.
Generally, I hear questions like this when the developer tries to use a DTO or even a database entity as a view model (both of which are incorrect uses).
I make sure each API method has a different view model (even if the contents are identical), because most of the time, eventually they will be different, but not always at the start.

Query parameter route constraints

I just started using ASP.NET Web API 2.1 and have encountered a limitation. Using Attribute Routing, I can do the following:
[Route("item/{id:int}")]
public IHttpActionResult GetItem(int id)
{
...
}
The URL /item/5 will be routed to this action, but the URL /item/abc will not, because of the int constraint in {id:int}.
I tried changing my URL so that the id parameter was in the query string along with its constraint, despite the use of route constraints on query parameters never being mentioned or demonstrated in the documentation.
[Route("item?{id:int}")]
public IHttpActionResult GetItem(int id)
{
...
}
If I try to run now, I get an error on the Configure method call in Application_Start.
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
The message is as follows.
ArgumentException was unhandled by user code
The route template cannot start with a '/' or '~' character and it cannot contain a '?' character.
Two things bother me about this.
First, the section documenting Route Prefixes on MSDN makes clear that placing a ~ character at the start of the route template is completely acceptable. I tried it, and it works as documented.
Second, if not like this, how can I place a route constraint on a query parameter? Consider the following, with the route constraint removed.
[Route("item")]
public IHttpActionResult GetItem(int id)
{
...
}
The URL /item/5 will be routed to this action, with id set to 5 - but so will the URL /item/abc, with id set to 0.
Is there no way to place a route constraint on a query parameter?
According to http://attributerouting.net/#asp-net-web-api (†), this is not possible:
"Beware! Due to integration issues with the Web API WebHost framework, the following features will not work: …
querystring parameter constraints, …"
†) Note that this answer was written for a previous version of Web API where attribute routing was done using a separate AttributeRouting.WebApi NuGet package. Attribute routing has since been incorporated into the Web API core. Nevertheless, it appears that constraints on query string parameters are still not supported out of the box.

"True" REST routing via MVC 4 Web API

TL;DR Summary: Can I configure MVC Web API routing for HTTP GET, PUT & DELETE?
I've been looking into replacing our old Data Access Layer (a DLL based on DataSets and TableAdapters) with a private API, with a view to creating a public API if it's successful. I've done some work with MVC 4 to refresh our frontend, and loved working with it, so it seems sensible to explore the "Web API" project type before diving into WS- or WCF-based libraries.
An initial demo allows me to return XML/JSON nicely, for example:
//service.url/api/Users
... returns a list of users, while a specific user's details can be accessed via:
//service.url/api/Users/99
So far, so RESTful. However, in order to truly map URIs to resources I want to do an HTTP PUT (new user) or HTTP DELETE (remove user) to the the URI listed above. In all of the examples I've seen for these projects, along with the Scaffolds provided in Visual Studio, this convention is followed:
//service.url/api/Users/Create
//service.url/api/Users/Delete/99
//service.url/api/Users/Update/99
... and so on. This feels like side-stepping the issue to me, which is a shame when what's there has been put together so nicely!
Any thoughts on how best to approach this?
What you want is the default in MVC Web API. I'm not sure what you are looking at but here is a great example of routing the Get/Post/Put/Delete to actions.
For example you may want:
public class UsersController : ApiController
{
// GET http://service.url/api/Users/1
[HttpGet]
public User GetUser(int id);
// POST http://service.url/api/Users/?name=richard...
[HttpPost]
public User AddUser(User model);
// PUT http://service.url/api/Users/?id=1&name=Richard...
[HttpPut]
public User UpdateUser(User model);
// DELETE http://service.url/api/Users/1
[HttpDelete]
public User DeleteUser(int id);
}
I've explicitly set these, but the GetUser and DeleteUser don't need the prefix because they start with the matching HTTP method.
The link provided by Erik is a good start, but I see how it can confuse the situation when looking for a simple RESTful API that makes use of the HTTP verbs to perform these CRUD actions. If you're looking to use the HTTP verbs of GET, PUT, POST, and DELETE (and possibly PATCH, but I'm not covering that here) and you're ok with using convention, then the following would work:
public class UsersController : ApiController
{
// GET http://service.url/api/Users
public User GetAllUsers(){ ... }
// GET http://service.url/api/Users/1
public User GetUser(int id){ ... }
// POST http://service.url/api/Users/
// User model is passed in body of HTTP Request
public User PostUser([FromBody]User model){ ... }
// PUT http://service.url/api/Users/1
// User model is passed in body of HTTP Request
public User PutUser(int id, [FromBody]User model){ ... }
// DELETE http://service.url/api/Users/1
public User DeleteUser(int id){ ... }
}
Note that the attributes on the method are not needed when using the HTTP verb action convention in Web API. Also, note that I use the [FromBody] attribute on the User parameter for POST and PUT to denote that the body contains the data I wish to send. This may not be most convenient for POST if you're trying to append to a resource, and I have not tried creating/modifying data through query parameters using Web API. It certainly makes the call feel very clean to place your data in the body. "POST/PUT this content in the body at this resource."
Also, the way I read PUT in the spec, and I could very well be wrong, is that it acts as a replace. That also makes sense given the last line above. I'm PUTting this resource in this location, replacing what was already there. The spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) states: "If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server." The term they use is "modified" so I guess that leaves enough room for interpretation for the end user. That's where PATCH comes in (https://www.rfc-editor.org/rfc/rfc5789), but I don't have enough information to comment on that at this time.

Categories

Resources