Skip to content

File-based routing #66

@Atulin

Description

@Atulin

Having to prefix all endpoints of a given type with a part of a path can be tedious and error-prone. What is not tedious or error-prone, is using the filesystem to drive routing.

Current state:

To have an endpoint at POST: /api/public/products we need:

// location: Api/Public/Products/CreateProduct.cs

[Handler]
[HttpPost("api/public/porducts")]
public static partial CreateProduct
{
    // ...
}

Can you spot the typo?

Proposed

To have an endpoint at POST: /api/public/products is as simple as:

// location: Api/Public/Products/CreateProduct.cs

[Handler]
[HttpPost]
public static partial CreateProduct
{
    // ...
}

Considerations

Opt-in methods

It does not have to be the default behavior. It could be controlled globally with some [assembly: FilesystemRouting] attribute, or perhaps on the individual endpoint basis with a similar attribute, or some magic like [HttpPost("[file]")] or [HttpPost(FilesystemRouting = true)]

Naming policies

What happens when a path contains a space? Should PascalCase directories be translated to lowercase, kebab-case, or something else?

The easiest way would be to go with what is the default for Microsoft, or at least seems to be: whitespace and special characters get removed, everything gets translated into PascalCase.

The best way would be to provide a choice, for example via an enum:

public enum NamingPolicy
{
    PascalCase,
    CamelCase,
    LowerCase,
    KebabCase,
    SnakeCase
}

to be used with attributes discussed prior, for example

[assembly: FileSystemRouting(
    NamingPolicy = NamingPolicy.LowerCase
)]

Base path

Endpoints don't always have to be placed in a directory at the root of the project. For various reasons, they can be placed elsewhere. A way should be provided to define the base directory. For example:

// location: Api/Handlers/Product/Create.cs

[assembly: FileSystemRouting(
    RootDirectory = "Api/Handlers"
)]

[Handler]
[MapPost] // maps it to POST: /product
public static partial class CreateProduct
{
    // ...
}

Source generator limitations

File location might not be available to a source generator. In such a case, should the namespace be used as a close approximation?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions