dimanche 21 décembre 2014

Web API Design Opinions

I'm in the process of building out a backend for a web application and I'm looking for some opinions on how to structure my web api. As this backend is going to be called from a variety of sources (mobile application, web frontend, administrative frontend), I'm trying to provide a flexible interface, while also considering simplicity and performance.


For the moment, imagine I have the following tables


product_type <-- really just an enum used for referential integrity.



  • id

  • name


product



  • id

  • name

  • product_type_id


product_batch



  • product_id


Because I'm unsure how the api is really going to be used at the moment, I'm tempted to treat each table as independent isolated resources and not nest them or provide any opinion on how the client wants the information. So, for example a GET to /api/1/products/1 will return {"id": "1", "name": "---", "product_type_id": "---"} -- notice that we don't join on product_type and just return the id.


For something like an administrative panel, this may be preferable, and maybe even for the mobile client as well.


The down side is of course performance -- more requests and not joining in the db where it will definitely be faster -- as well as exposing internal structure.


The benefit, however, is that the client has a solid interface from which behavior can be more easily derived: if GET /ap/1/products/1 returned the product with the product_batches nested inside, and the client modified a nested product_batch and PUT back to the same resource, then it's not clear whether we should actually update the product batches and if we do, then we have to have product_batch logic inside the product resource and that's messy -- I don't even want products to know about product_batches. Furthermore, the client may cache the response from /api/1/productTypes and not have to make two calls for each product, so there are ways to address the performance issue.


With this in mind, I'm completely aware that a more opinionated interface may be more desirable for certain circumstances. To deal with this, I'm considering structuring the above "raw" api endpoints under "resources": /api/1/resources/products, /api/1/resources/productTypes, etc.. Then I would expose the opinionated "views" under something /api/1/views/product or /api/1/views/productsWithBatches or /api/1/views/products?withBatches=true -- these are all GET's, no POST, PUT, or DELETE on views .... I don't know.


Of course I can just have a query param that signifies "includeBatches" or something on the actual resource, but the reason I don't like this is that I then have an endpoint returning different models for different parameters, and consuming models (through POST, PUT) different than it produces -- this just leads to more difficulty in managing client models.


Another wild idea I've been thinking of is batching requests: the client sends a list of endpoints and the server runs through the list calling each endpoint as if the client did, and aggregating the results in a list for a response. There are plenty of pitfalls with this, but the benefit is that the client can get a bunch of information with one call; however, it may be better to just have a "view" for this as then we can properly join the information in the sql query when needed, and reduce db calls.





Aucun commentaire:

Enregistrer un commentaire