1

Basically there are two things which are important for me. The first one is already answered in the same way I would've done it (How to model a RESTful API with inheritance?). The RESTful design is easier to maintain when realized like:

GET /animals        # get all animals
POST /animals       # create a dog or cat
GET /animals/123    # get animal 123

Instead of:

GET /dogs       # get all dogs
POST /dogs      # create a dog
GET /dogs/123   # get dog 123

GET /cats       # get all cats
POST /cats      # create a cat
GET /cats/123   # get cat 123

I don't know how to setup a proper way of deserializing the following code into for example an object of type dog. I tend to get confused since most people advice on creating only an /animals POST endpoint instead of /animals/dog POST, but don't provide a direct solution to this.

The solutions I've found are:

  • TypeNameHandling.Auto (not secure unless custom serializer?)

  • Custom JsonConverter which also needs a custom implementation to tell which fields are in the derived classes as far as I'm concerned

  • JsonSubTypes(typeof(...)) annotation. This also needs including of fields from the derived classes in the custom mapping.

In the end I want to achieve the following. If this means this 'generic' solution in the end is not worth it, that's also an answer for me.

 [HttpPost]
 public async Task<ActionResult> Add(Animal animal)
 {
     // repo.add(animal);
 }
Rvh
  • 43
  • 6
  • show your classes aka your code, the object themselves would be able to handle it depending on what your code looks like, class -> BaseAnimal -> property bool HasFur. The serialized version would look like same as if it was in one class and wouldn't know about any base classes, you can then deserialize to the specific animal, you would have to deserialize to animal, then you could ask at run-time, what type of animal and then cast to that type. So you would perhaps need to deserialize twice, once to get the type of animal then to deserialize to that animal. – Seabizkit Dec 10 '19 at 09:50
  • But the problem is to do this directly from the controller. I used the typical 'animal' base class and 'dog', 'cat' derived class example. For me it is regardless the properties the derived classes have. – Rvh Dec 10 '19 at 10:24
  • i think i get what your saying, but the answer in the link you quoted was the best, from what i can see.. you need to split api calls into the way they are doing it... where the animal call, exposes what calls you can then call... like what they doing in your link, the answer is demonstrating this. – Seabizkit Dec 10 '19 at 11:24
  • 1
    Yes I could also not figure out another way to do it but I was interested in what people generally do. So it seems that there will be (a lot) derived resources. Thanks for your input :) – Rvh Dec 10 '19 at 12:20
  • marked up i agree, would be interesting if there are some more ways of approaching this. – Seabizkit Dec 11 '19 at 07:37

1 Answers1

1

Why not use the Route attribute?

So your route would look like

POST animals/dog

All you need to do is the following:

[HttpPost]
[Route("dog")]
public Task<IActionResult> AddDog(Dog dog)

That will produce the route

localhost:PORT/animals/dog

That way its all contained in the one controller and the URIs are coming off of the central animals one.

Due to the way that things get serialised I don't think there is a way you can just post a generic Animal and it know to go to a dog or cat. You would need to write a custom deserialiser for that

GingerNeil
  • 106
  • 2
  • It is suggested by the article I followed to make only one endpoint which posts 'any' animal. The frontend is actually sending a dog with it's corresponding properties. My question is about realizing it so I can use POST animals/. – Rvh Dec 10 '19 at 10:24
  • Ah I get what you're meaning now! Sorry mate! What I would do is put a property into the base class like Type or something and in the controller method when the base class has been deserialised you can check for that Type property IE Dog or Cat. From there you can get the request stream and just re-deserialise into the correct abstraction. – GingerNeil Dec 10 '19 at 10:58
  • I was already afraid of this. What you suggest is probably a good solution, but I was hoping for something easier or more readable. Thanks for your input. I will mark your answer as solved since I think this is just a better way to solve the problem in the end. Eventhough it will result in some more endpoints. – Rvh Dec 10 '19 at 12:22
  • Why not check out GraphQL? It provides a single end point and behind the scenes does checks to see where the data should be processed/gotten from and in what way? – GingerNeil Dec 10 '19 at 12:38