David Liang
David Liang

Reputation: 21476

ServiceStack custom route variable placeholder doesn't have any constraint validation?

I have 2 endpoints built by ServiceStack services:

Delete parent: /parents/{parentId}

[Api("Delete a parent")]
[Tag("Parent")]
[Route("/parents/{parentId}", HttpMethods.Delete)]
public class DeleteParentRequest : IReturnVoid
{
    [ApiMember(ParameterType = "path", IsRequired = true)]
    public int ParentId { get; set; }
}

[Authenticate]
public class ParentService : Service
{
    ...

    public void Delete(DeleteParentRequest request)
    {
        // Logic to delete parent, along with all its children
    }
}

Delete Parent Child: /parents/{parentId}/children/{childId}

[Api("Delete a parent child")]
[Tag("Parent Child")]
[Route("/parents/{parentId}/children/{childId}", HttpMethods.Delete)]
public class DeleteParentChildRequest : IReturnVoid
{
    [ApiMember(ParamterType = "path", IsRequired = true)]
    public int ParentId { get; set; }

    [ApiMember(ParameterType = "path", IsRequired = true)]
    public int ChildId { get; set; }
}

[Authenticate]
public class ParentChildService : Service
{
    ...

    public void Delete(DeleteParentChildRequest request)
    {
        // Delete the parent child
    }
}

These 2 endpoints are working as expected.

Unfortunately (or actually fortunately), our QA passed the wrong endpoint when testing the delete child endpoint. What he put on Postman was DELETE: /parents/children?parentId=1&other=rndString.

What I expect when we call that wrong endpoint is that we should get a 404 not found, since it doesn't match with any of our endpoints. But surprisingly, it actually called the delete-parent endpoint DELETE: /parents/{parentId}.

How would that happen, even I already have a matching integer property called ParentId in the request DTO that tells ServiceStack that I am expecting an integer from the route? Does ServiceStack have its own routing constraints? Or do I have to implement myself?

Upvotes: 1

Views: 47

Answers (1)

mythz
mythz

Reputation: 143319

There are no constraints on the Route Path itself, i.e. this definition:

[Route("/parents/{parentId}", HttpMethods.Delete)]

Will match every DELETE request that matches the route, i.e:

DELETE /parents/1
DELETE /parents/foo

You can apply routing constraints with a Custom Route Rule, e.g:

[Route("/parents/{parentId}", HttpMethods.Delete, Matches = "**/{int}")]

Will apply the built-in **/{int} route rule to only match routes where the last segment is an integer, i.e:

DELETE /parents/1

Upvotes: 2

Related Questions