[csharp] Add a server generator for FastEndpoints (#19690)

* Add of a first working generator for FastEndpoints framework

Generator that support the basics of a FastEndpoints project
https://fast-endpoints.com/

* Add respose code documentation support

* Add an option to enable use of problem details

* Clean enum and model

* Add an option to generate record for requests/models

* Update sample

* Add support of nullable types

* Add option to enable authentication

* Add option to generate validators

* Clean readme.md file

* Add option to enable response caching

* update readme template

* Add missing files references

* Update generated sample

* Add link to documentation

* Add generator documentation

* correctly support packageName

supportingFiles additions moved to processOpts()

* improve useAuthentication option handling

Avoid to copy an empty file

* processOpts, move call to parent at the end

* Update generated sample

* Refactor and fix super.processOpts(); call order

* Handle the case of multi-line description

* Rename field to match naming conventions

* Add useApiVersioning option

* Update generated sample

* Add generator documentation

* Fix record when model contains optional properties

* Add configuration files for each option

* Add sample project for each configuration

* Add GitHub Action workflow for sample projects

* Add FastEndpoints BindFrom attribute on path, query and form params

* Update sample generated projects

* Fix validator template

* fix alphabetical order

* Use fully qualified name for FastEndpoints

* Add options to set GUID to be used in sln file

* update sample projects

* Update generators.md

* Fix path in github workflow

* Put readme, gitignore and solution file at the root of generated project

* update sample projects

* Remove the projectGuid option

This Guid need to be constant, it is related to project type

* update sample projects
This commit is contained in:
Julien Tschäppät
2024-11-07 13:28:29 +01:00
committed by GitHub
parent e2553a4a91
commit 7deecdc569
196 changed files with 14406 additions and 0 deletions

View File

@@ -0,0 +1,9 @@

namespace Org.OpenAPITools.Features;
public class LoginRequest
{
public string Username { get; set; }
public string Password { get; set; }
}

View File

@@ -0,0 +1,316 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
/// <summary>
/// Add a new pet to the store
/// </summary>
public class AddPetEndpoint : FastEndpoints.Endpoint<AddPetRequest, Pet>
{
public override void Configure()
{
Post("/v2/pet");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 405);
});
Summary(s => {
s.Summary = "Add a new pet to the store";
s.RequestParam(r => r.pet, "Pet object that needs to be added to the store");
s.Responses[200] = "successful operation";
s.Responses[405] = "Invalid input";
});
}
public override async Task HandleAsync(AddPetRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Deletes a pet
/// </summary>
public class DeletePetEndpoint : FastEndpoints.Endpoint<DeletePetRequest>
{
public override void Configure()
{
Delete("/v2/pet/{petId}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
});
Summary(s => {
s.Summary = "Deletes a pet";
s.RequestParam(r => r.PetId, "Pet id to delete");
s.RequestParam(r => r.ApiKey, "");
s.Responses[400] = "Invalid pet value";
});
}
public override async Task HandleAsync(DeletePetRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Finds Pets by status
/// </summary>
public class FindPetsByStatusEndpoint : FastEndpoints.Endpoint<FindPetsByStatusRequest, List<Pet>>
{
public override void Configure()
{
Get("/v2/pet/findByStatus");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
});
Summary(s => {
s.Summary = "Finds Pets by status";
s.RequestParam(r => r.Status, "Status values that need to be considered for filter");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid status value";
});
}
public override async Task HandleAsync(FindPetsByStatusRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Finds Pets by tags
/// </summary>
[Obsolete]
public class FindPetsByTagsEndpoint : FastEndpoints.Endpoint<FindPetsByTagsRequest, List<Pet>>
{
public override void Configure()
{
Get("/v2/pet/findByTags");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
});
Summary(s => {
s.Summary = "Finds Pets by tags";
s.RequestParam(r => r.Tags, "Tags to filter by");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid tag value";
});
}
public override async Task HandleAsync(FindPetsByTagsRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Find pet by ID
/// </summary>
public class GetPetByIdEndpoint : FastEndpoints.Endpoint<GetPetByIdRequest, Pet>
{
public override void Configure()
{
Get("/v2/pet/{petId}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Find pet by ID";
s.RequestParam(r => r.PetId, "ID of pet to return");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid ID supplied";
s.Responses[404] = "Pet not found";
});
}
public override async Task HandleAsync(GetPetByIdRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Update an existing pet
/// </summary>
public class UpdatePetEndpoint : FastEndpoints.Endpoint<UpdatePetRequest, Pet>
{
public override void Configure()
{
Put("/v2/pet");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 405);
});
Summary(s => {
s.Summary = "Update an existing pet";
s.RequestParam(r => r.pet, "Pet object that needs to be added to the store");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid ID supplied";
s.Responses[404] = "Pet not found";
s.Responses[405] = "Validation exception";
});
}
public override async Task HandleAsync(UpdatePetRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Updates a pet in the store with form data
/// </summary>
public class UpdatePetWithFormEndpoint : FastEndpoints.Endpoint<UpdatePetWithFormRequest>
{
public override void Configure()
{
Post("/v2/pet/{petId}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("pet");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 405);
});
Summary(s => {
s.Summary = "Updates a pet in the store with form data";
s.RequestParam(r => r.PetId, "ID of pet that needs to be updated");
s.RequestParam(r => r.Name, "Updated name of the pet");
s.RequestParam(r => r.Status, "Updated status of the pet");
s.Responses[405] = "Invalid input";
});
}
public override async Task HandleAsync(UpdatePetWithFormRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// uploads an image
/// </summary>
public class UploadFileEndpoint : FastEndpoints.Endpoint<UploadFileRequest, ApiResponse>
{
public override void Configure()
{
Post("/v2/pet/{petId}/uploadImage");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
AllowFileUploads();
Description(x =>
{
x.WithTags("pet");
});
Summary(s => {
s.Summary = "uploads an image";
s.RequestParam(r => r.PetId, "ID of pet to update");
s.RequestParam(r => r.AdditionalMetadata, "Additional data to pass to server");
s.RequestParam(r => r.File, "file to upload");
s.Responses[200] = "successful operation";
});
}
public override async Task HandleAsync(UploadFileRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,97 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
public class AddPetRequest
{
/// <summary>
/// Pet object that needs to be added to the store
/// </summary>
[FastEndpoints.FromBody]
public Pet pet { get; set; }
}
public class DeletePetRequest
{
/// <summary>
/// Pet id to delete
/// </summary>
[FastEndpoints.BindFrom("petId")]
public long PetId { get; set; }
/// <summary>
///
/// </summary>
[FastEndpoints.FromHeader]
public string? ApiKey { get; set; }
}
public class FindPetsByStatusRequest
{
/// <summary>
/// Status values that need to be considered for filter
/// </summary>
[FastEndpoints.QueryParam, FastEndpoints.BindFrom("status")]
public List<string> Status { get; set; }
}
public class FindPetsByTagsRequest
{
/// <summary>
/// Tags to filter by
/// </summary>
[FastEndpoints.QueryParam, FastEndpoints.BindFrom("tags")]
public List<string> Tags { get; set; }
}
public class GetPetByIdRequest
{
/// <summary>
/// ID of pet to return
/// </summary>
[FastEndpoints.BindFrom("petId")]
public long PetId { get; set; }
}
public class UpdatePetRequest
{
/// <summary>
/// Pet object that needs to be added to the store
/// </summary>
[FastEndpoints.FromBody]
public Pet pet { get; set; }
}
public class UpdatePetWithFormRequest
{
/// <summary>
/// ID of pet that needs to be updated
/// </summary>
[FastEndpoints.BindFrom("petId")]
public long PetId { get; set; }
/// <summary>
/// Updated name of the pet
/// </summary>
[FastEndpoints.BindFrom("name")]
public string? Name { get; set; }
/// <summary>
/// Updated status of the pet
/// </summary>
[FastEndpoints.BindFrom("status")]
public string? Status { get; set; }
}
public class UploadFileRequest
{
/// <summary>
/// ID of pet to update
/// </summary>
[FastEndpoints.BindFrom("petId")]
public long PetId { get; set; }
/// <summary>
/// Additional data to pass to server
/// </summary>
[FastEndpoints.BindFrom("additionalMetadata")]
public string? AdditionalMetadata { get; set; }
/// <summary>
/// file to upload
/// </summary>
[FastEndpoints.BindFrom("file")]
public System.IO.Stream? File { get; set; }
}

View File

@@ -0,0 +1,157 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
/// <summary>
/// Delete purchase order by ID
/// </summary>
public class DeleteOrderEndpoint : FastEndpoints.Endpoint<DeleteOrderRequest>
{
public override void Configure()
{
Delete("/v2/store/order/{orderId}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("store");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Delete purchase order by ID";
s.RequestParam(r => r.OrderId, "ID of the order that needs to be deleted");
s.Responses[400] = "Invalid ID supplied";
s.Responses[404] = "Order not found";
});
}
public override async Task HandleAsync(DeleteOrderRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Returns pet inventories by status
/// </summary>
public class GetInventoryEndpoint : FastEndpoints.EndpointWithoutRequest<Dictionary<string, int>>
{
public override void Configure()
{
Get("/v2/store/inventory");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("store");
});
Summary(s => {
s.Summary = "Returns pet inventories by status";
s.Responses[200] = "successful operation";
});
}
public override async Task HandleAsync(CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Find purchase order by ID
/// </summary>
public class GetOrderByIdEndpoint : FastEndpoints.Endpoint<GetOrderByIdRequest, Order>
{
public override void Configure()
{
Get("/v2/store/order/{orderId}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("store");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Find purchase order by ID";
s.RequestParam(r => r.OrderId, "ID of pet that needs to be fetched");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid ID supplied";
s.Responses[404] = "Order not found";
});
}
public override async Task HandleAsync(GetOrderByIdRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Place an order for a pet
/// </summary>
public class PlaceOrderEndpoint : FastEndpoints.Endpoint<PlaceOrderRequest, Order>
{
public override void Configure()
{
Post("/v2/store/order");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("store");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
});
Summary(s => {
s.Summary = "Place an order for a pet";
s.RequestParam(r => r.order, "order placed for purchasing the pet");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid Order";
});
}
public override async Task HandleAsync(PlaceOrderRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,35 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
public class DeleteOrderRequest
{
/// <summary>
/// ID of the order that needs to be deleted
/// </summary>
[FastEndpoints.BindFrom("orderId")]
public string OrderId { get; set; }
}
public class GetInventoryRequest
{
}
public class GetOrderByIdRequest
{
/// <summary>
/// ID of pet that needs to be fetched
/// </summary>
[FastEndpoints.BindFrom("orderId")]
public long OrderId { get; set; }
}
public class PlaceOrderRequest
{
/// <summary>
/// order placed for purchasing the pet
/// </summary>
[FastEndpoints.FromBody]
public Order order { get; set; }
}

View File

@@ -0,0 +1,310 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
/// <summary>
/// Create user
/// </summary>
public class CreateUserEndpoint : FastEndpoints.Endpoint<CreateUserRequest>
{
public override void Configure()
{
Post("/v2/user");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 0);
});
Summary(s => {
s.Summary = "Create user";
s.RequestParam(r => r.user, "Created user object");
s.Responses[0] = "successful operation";
});
}
public override async Task HandleAsync(CreateUserRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Creates list of users with given input array
/// </summary>
public class CreateUsersWithArrayInputEndpoint : FastEndpoints.Endpoint<CreateUsersWithArrayInputRequest>
{
public override void Configure()
{
Post("/v2/user/createWithArray");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 0);
});
Summary(s => {
s.Summary = "Creates list of users with given input array";
s.RequestParam(r => r.user, "List of user object");
s.Responses[0] = "successful operation";
});
}
public override async Task HandleAsync(CreateUsersWithArrayInputRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Creates list of users with given input array
/// </summary>
public class CreateUsersWithListInputEndpoint : FastEndpoints.Endpoint<CreateUsersWithListInputRequest>
{
public override void Configure()
{
Post("/v2/user/createWithList");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 0);
});
Summary(s => {
s.Summary = "Creates list of users with given input array";
s.RequestParam(r => r.user, "List of user object");
s.Responses[0] = "successful operation";
});
}
public override async Task HandleAsync(CreateUsersWithListInputRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Delete user
/// </summary>
public class DeleteUserEndpoint : FastEndpoints.Endpoint<DeleteUserRequest>
{
public override void Configure()
{
Delete("/v2/user/{username}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Delete user";
s.RequestParam(r => r.Username, "The name that needs to be deleted");
s.Responses[400] = "Invalid username supplied";
s.Responses[404] = "User not found";
});
}
public override async Task HandleAsync(DeleteUserRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Get user by user name
/// </summary>
public class GetUserByNameEndpoint : FastEndpoints.Endpoint<GetUserByNameRequest, User>
{
public override void Configure()
{
Get("/v2/user/{username}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Get user by user name";
s.RequestParam(r => r.Username, "The name that needs to be fetched. Use user1 for testing.");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid username supplied";
s.Responses[404] = "User not found";
});
}
public override async Task HandleAsync(GetUserByNameRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Logs user into the system
/// </summary>
public class LoginUserEndpoint : FastEndpoints.Endpoint<LoginUserRequest, string>
{
public override void Configure()
{
Get("/v2/user/login");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
});
Summary(s => {
s.Summary = "Logs user into the system";
s.RequestParam(r => r.Username, "The user name for login");
s.RequestParam(r => r.Password, "The password for login in clear text");
s.Responses[200] = "successful operation";
s.Responses[400] = "Invalid username/password supplied";
});
}
public override async Task HandleAsync(LoginUserRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Logs out current logged in user session
/// </summary>
public class LogoutUserEndpoint : FastEndpoints.EndpointWithoutRequest
{
public override void Configure()
{
Get("/v2/user/logout");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 0);
});
Summary(s => {
s.Summary = "Logs out current logged in user session";
s.Responses[0] = "successful operation";
});
}
public override async Task HandleAsync(CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}
/// <summary>
/// Updated user
/// </summary>
public class UpdateUserEndpoint : FastEndpoints.Endpoint<UpdateUserRequest>
{
public override void Configure()
{
Put("/v2/user/{username}");
//TODO : authentication is enabled, you need to configure the authorizations : https://fast-endpoints.com/docs/security#endpoint-authorization
Description(x =>
{
x.WithTags("user");
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 400);
FastEndpoints.RouteHandlerBuilderExtensions.ProducesProblemFE(x, 404);
});
Summary(s => {
s.Summary = "Updated user";
s.RequestParam(r => r.Username, "name that need to be deleted");
s.RequestParam(r => r.user, "Updated user object");
s.Responses[400] = "Invalid user supplied";
s.Responses[404] = "User not found";
});
}
public override async Task HandleAsync(UpdateUserRequest req, CancellationToken ct)
{
//Response = new()
//{
//...
//};
//return Task.CompletedTask;
}
}

View File

@@ -0,0 +1,77 @@
using Org.OpenAPITools.Models;
namespace Org.OpenAPITools.Features;
public class CreateUserRequest
{
/// <summary>
/// Created user object
/// </summary>
[FastEndpoints.FromBody]
public User user { get; set; }
}
public class CreateUsersWithArrayInputRequest
{
/// <summary>
/// List of user object
/// </summary>
[FastEndpoints.FromBody]
public List<User> user { get; set; }
}
public class CreateUsersWithListInputRequest
{
/// <summary>
/// List of user object
/// </summary>
[FastEndpoints.FromBody]
public List<User> user { get; set; }
}
public class DeleteUserRequest
{
/// <summary>
/// The name that needs to be deleted
/// </summary>
[FastEndpoints.BindFrom("username")]
public string Username { get; set; }
}
public class GetUserByNameRequest
{
/// <summary>
/// The name that needs to be fetched. Use user1 for testing.
/// </summary>
[FastEndpoints.BindFrom("username")]
public string Username { get; set; }
}
public class LoginUserRequest
{
/// <summary>
/// The user name for login
/// </summary>
[FastEndpoints.QueryParam, FastEndpoints.BindFrom("username")]
public string Username { get; set; }
/// <summary>
/// The password for login in clear text
/// </summary>
[FastEndpoints.QueryParam, FastEndpoints.BindFrom("password")]
public string Password { get; set; }
}
public class LogoutUserRequest
{
}
public class UpdateUserRequest
{
/// <summary>
/// name that need to be deleted
/// </summary>
[FastEndpoints.BindFrom("username")]
public string Username { get; set; }
/// <summary>
/// Updated user object
/// </summary>
[FastEndpoints.FromBody]
public User user { get; set; }
}

View File

@@ -0,0 +1,45 @@

using FastEndpoints;
using FastEndpoints.Security;
namespace Org.OpenAPITools.Features;
//TODO: This is a placeholder for the actual login request endpoint
// For more information : https://fast-endpoints.com/docs/security
public class UserLoginEndpoint : Endpoint<LoginRequest>
{
public override void Configure()
{
Post("/api/login");
AllowAnonymous();
}
public override async Task HandleAsync(LoginRequest req, CancellationToken ct)
{
bool credentialsAreValid = true; //TODO call your authentication service
if (credentialsAreValid)
{
var jwtToken = JwtBearer.CreateToken(
o =>
{
o.SigningKey = "A secret token signing key";
o.ExpireAt = DateTime.UtcNow.AddDays(1);
o.User.Roles.Add("Manager", "Auditor");
o.User.Claims.Add(("UserName", req.Username));
o.User["UserId"] = "001"; //indexer based claim setting
});
await SendAsync(
new
{
req.Username,
Token = jwtToken
});
}
else
{
ThrowError("The supplied credentials are invalid!");
}
}
}

View File

@@ -0,0 +1,14 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// Describes the result of uploading an image resource
/// </summary>
public class ApiResponse
{
public int Code { get; set; }
public string Type { get; set; }
public string Message { get; set; }
}

View File

@@ -0,0 +1,13 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// A category for a pet
/// </summary>
public class Category
{
public long Id { get; set; }
public string Name { get; set; }
}

View File

@@ -0,0 +1,41 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// An order for a pets from the pet store
/// </summary>
public class Order
{
public long Id { get; set; }
public long PetId { get; set; }
public int Quantity { get; set; }
public DateTime ShipDate { get; set; }
/// <summary>
/// Order Status
/// </summary>
/// <value>Order Status</value>
public enum StatusEnum
{
/// <summary>
/// Enum PlacedEnum for placed
/// </summary>
PlacedEnum = 1,
/// <summary>
/// Enum ApprovedEnum for approved
/// </summary>
ApprovedEnum = 2,
/// <summary>
/// Enum DeliveredEnum for delivered
/// </summary>
DeliveredEnum = 3
}
public StatusEnum Status { get; set; }
public bool Complete { get; set; } = false;
}

View File

@@ -0,0 +1,41 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// A pet for sale in the pet store
/// </summary>
public class Pet
{
public long Id { get; set; }
public Category Category { get; set; }
public string Name { get; set; }
public List<string> PhotoUrls { get; set; }
public List<Tag> Tags { get; set; }
/// <summary>
/// pet status in the store
/// </summary>
/// <value>pet status in the store</value>
public enum StatusEnum
{
/// <summary>
/// Enum AvailableEnum for available
/// </summary>
AvailableEnum = 1,
/// <summary>
/// Enum PendingEnum for pending
/// </summary>
PendingEnum = 2,
/// <summary>
/// Enum SoldEnum for sold
/// </summary>
SoldEnum = 3
}
public StatusEnum Status { get; set; }
}

View File

@@ -0,0 +1,13 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// A tag for a pet
/// </summary>
public class Tag
{
public long Id { get; set; }
public string Name { get; set; }
}

View File

@@ -0,0 +1,19 @@
namespace Org.OpenAPITools.Models;
/// <summary>
/// A User who is purchasing from the pet store
/// </summary>
public class User
{
public long Id { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string Phone { get; set; }
public int UserStatus { get; set; }
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FastEndpoints" Version="5.29.0" />
<PackageReference Include="FastEndpoints.Security" Version="5.29.0" />
<PackageReference Include="FastEndpoints.Swagger" Version="5.29.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,40 @@
using FastEndpoints;
using FastEndpoints.Security;
using FastEndpoints.Swagger;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddAuthenticationJwtBearer(s => s.SigningKey = "The secret used to sign tokens") //TODO set the signing key
.AddAuthorization()
.AddFastEndpoints()
.SwaggerDocument(o =>
{
o.DocumentSettings = s =>
{
s.DocumentName = "OpenAPI Petstore";
s.Title = "OpenAPI Petstore";
s.Description = """
This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
""";
s.Version = "1.0.0";
};
o.AutoTagPathSegmentIndex = 0;
})
;
var app = builder.Build();
app
.UseAuthentication()
.UseAuthorization()
.UseFastEndpoints(x =>
{
})
.UseSwaggerGen();
app.UseHttpsRedirection();
app.Run();

View File

@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52621",
"sslPort": 44314
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5198",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7047;http://localhost:5198",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}