Best approach for api versioning while adding new business validation - rest

I have a project to maintain the user and his/her project allocation records. The project exposes REST APIs to support user/project CRUD operations.
The REST endpoints are designed to support backward compatibility using REST API versioning so that any new changes in the REST API should not affect the existing consumer of that API.
I have the below use case where I need suggestions for the best approach:
At first, the business requirement was that a user can be deleted irrespective of his/her allocation to some project and hence the REST API to delete the user was created with version v1 to support this.
But then there was a change in the requirement that a user cannot be deleted if he/she is allocated some project.
This is a change in business validation. Should I create a new version(v2) of user DELETE REST API to support this business validation or I should add this business validation to the existing version(v1) of user DELETE REST API?
My viewpoint:
If I will expose two versions of the user DELETE REST API then the database can have records with deleted users with as well as without project

I would argue that this is more of an implementation detail of the backing store. In all likelihood, the storage mechanism for both is almost certainly the same.
I would not change the DELETE API nor version it because the contract is 100% the same over the wire. A client has no idea how it's implemented behind the scenes; they're not supposed to anyway. The implementation needs to change such that a DELETE always results in a soft delete after some point in time (e.g. when you publish the new version). If you version DELETE you also open things up where clients can do things you don't intend; for example, triggering a real deletion by using a specific version of the API.
The thing that needs to change is how the older APIs deal with all of the other supported methods such as GET, POST, PATCH, and so on. The older APIs should yield 404 for a soft deleted resource (implying that DELETE was permanent). POST is probably the most unusual case. This could return 409, but that implies the resource exists or it could result in an update that also undeletes the existing resource. This API would likely even continue to return 201, implying the resource was created when it was really just updated in storage.
Remember that Representational State Transfer is just a representation of your business logic. Keep the APIs the same (and thus clients from breaking) and adjust the implementation to adapt to new rules. The DELETE API is unchanged (and usually version-neutral). Clients don't know what the man behind the curtain is doing. If things continue to behave the same over the wire, clients are none the wiser.
I hope that helps.

Related

flutter rest api I want to delete all pushes

I am using rest api. I want to delete all pushes, but I don't know how to write the query.
I know how to delete a specific push.
delete $apiUrl/pushes/$pushId
What I want is to delete all pushes for that user.
$apiUrl/pushes?owner=$ownerId/ ???
thank you
I would recommend 2 approaches
Do it in a non-rest way by sending a custom JSON object containing the ID's marked for deletion. Reference
Mozilla Storage Service SyncStorage API - to delete multiple records using REST. Reference
REST isn't the only way to solve any problem. “REST” is just an architectural style and you don't have to adhere to it (but you lose certain benefits of the internet if you don't). I suggest you look down this list of HTTP API architectures and pick the one that suits you.

Call Web Service when contents change

We'd like to allow our users to make changes to our ERP (only very limited conditions) from within the smartsheet. Is there a way to add a web service call based on changes to a cell?
It's certainly possible to do what you've described (provided, of course, that your ERP supports inbound web service calls to update data there).
If you're wanting to do this programmatically (i.e., by writing a script in Python or any other supported language), you can use the Smartsheet API to create one or more webhooks that will monitor Smartsheet for the type of changes you specify, and send your integration notifications when those events occur. Your integration would then listen for those inbound event notifications, and when they are received, it would programmatically issue the appropriate web service call(s) to update data in the ERP.
It's also worth mentioning that, depending on what ERP you're using, it may be possible for you to accomplish your goal without having to write any code. If you're interested in exploring the feasibility of that approach, I'd suggest you check out products like Zapier, Power Automate, etc. to see if they offer a connector for Smartsheet and your ERP. You may also want to check out the Smartsheet Connectors and Integrations page to see if there's a connector for your ERP listed there.

RESTful design for accessing the same resource in different formats from different audiences

Use case
I am building a webshop where people can register/sign in and can purchase (and afterwards manage) their SaaS licenses. For this purpose I created (among others) the following REST endpoints:
// Lists all licenses which are linked to this user
r.Get("/users/{userID}/licenses", api.LicenseSvc.HandleGetLicenses())
// List details (such as purchase date, seat information, ...) for a given licenseID
r.Get("/users/{userID}/licenses/{licenseID}", api.LicenseSvc.HandleGetLicense())
// Creates a new license for the signed in user
r.Post("/users/{userID}/licenses", api.LicenseSvc.HandleCreateLicense())
// Each license has a limited number of seats. The license manager can free up seats to make room for others
r.Delete("/users/{userID}/licenses/{licenseID}/seats/{seatID}", api.LicenseSvc.HandleDeleteSeat())
The above endpoints are only supposed to be used in the webshop/license management panel. At the same time the same service has to serve endpoints for the SaaS products which actually use the license(s) a user has created/purchased before. This SaaS product needs different endpoints such as:
An endpoint to check at startup whether a given license is valid at all
An endpoint which also gets the license by ID (see above), but it should only return a subset of the license resource (e. g. it shouldn't return the date when the license was purchased)
My question
Due to the fact that I am building one REST API which is consumed by two different "audiences" (on the one hand the license manager/customer and on the other hand the SaaS software) I feel like I am running into conflicts.
The authentication of both audiences is different, both audiences want to access the same kind of resource (e. g. a license) but the resource "format" (no customer sensitive data for the SaaS requester) should be different depending on the audience.
Should this be reflected via different REST URLs or should I handle all that logic inside of my route handlers?
Should I even create two different services serving these different audiences? Like one API for the userpanel/license management and one for the SaaS products!?
REST is not very well prepared for these multi-client scenarios. i have seen many REST apis where certain attributes of resources will only be filled under certain circumstances where i find that perfectly fine. however i have also seen many examples of multiple use cases bunched into single resource models where the swagger documentation with its limiting structure terribly fails to communicate the purpose of each field.
so: as long as the use cases do not differ too much, i would try to keep the count of endpoints low.
tip: have a look at GraphQL, it is much better equipped for handling such cases with querying only for certain sets or even only asking for certain fields, putting the client in control. however using GraphQL as the primary interface is still somewhat exotic and comes with quite substantial initial cost compared to the plentiful REST infrastructure available. still worth it.

Making DB Query as a Microservice API

We are currently using direct DB connection to query mongodb from our scripts and retrieve the required data.
Is it advisable / best practice to make the data retrieval from DB as a microservice.
It does until it doesn't :)
A service needs to get its data from somewhere and a database is a good start. If you have high loads you may find that you need to add a cache in the middle see this post from Instagram engineering https://instagram-engineering.com/thundering-herds-promises-82191c8af57d
edit (after comment)
generally speaking, a service should own its database and other services shouldn't access another database service directly only via its API. The idea is to keep services autonomous and enable them to evolve independently.
Depending on the size of microservice, that's now always practical since it can make the overhead of having the service be more of the utility it provide (I call this nanoservices). Also, if you have a lot of services you don't want to allow each one to talk to any other (even not via the DB) since you just get a huge mess. The way I see it there should be clear logical boundaries (services or microservices) and then within each such logical services you may find that it makes sense to have more than one "parts" (which I call aspects) e.g. they have different scaling needs or different suitable technologies etc. When you set things this way aspects can access the same database and services shouldn't (and you can still tame the chaos :) )
One last thing to think about - who said API is only a REST API, you can add views on top of the data that belongs to another service and as long as you treat that like an API (security, versioning etc.) you can have other services access that as well

Comparing data with RESTful API

For a website I am working on defining a RESTful API. I believe I got it (mostly) correct using proper resource URIs and proper use of GET/POST/UPDATE/DELETE.
However there is one point where I can't quite figure out what the proper way to do it "in" REST would be - comparison of lists.
Let's say I have a bookstore and a customer can have a wishlist. The wishlist consists of books (their full Book record, i.e. name, synopsis, etc) and a full copy of the list exists on the client. What would be a good way to design the RESTful API to allow a client to query the correctness of its local wishlist (i.e. get to know what books have been added/removed on the wishlist on the server side)?
One option would be to just download the full wishlist from the server and compare it locally. However this is quite a large amount of data (due to the embedded content) and this is a mobile client with a low-bandwidth connection, so this would cause a lot of problems.
Another option would be to download not the whole wishlist (i.e. not including book infos) but only a list of the books' identifiers. This would be not much data (compared to the previous option) and the client could compare the lists locally. However to get the full book record for newly added books, a REST call would have to be made for every single new book. Again, as this is a mobile client with bad network connectivity, this could be problematic.
A third option and my favorite, would be that the client sends its list of identifiers to the server and the server compares it to the wishlist and returns what books were removed and the data for books that were added. This would mean a single roundtrip and only the necessary amount of data. As the wishlist size is estimated to be less than 100 entries, sending just the IDs would be a minimal amount of data (~0.5kb). However I don't know what kind of call would be appropriate - it can't be GET as we are sending data (and putting it all in the URL does not feel right), it can't be POST/UPDATE as we do not change anything on the server. Obviously it's not DELETE either.
How would you implement this third option?
Side-question: how would you solve this problem (i.e. why is option 3 stupid or what better, simple solutions may there be)?
Thank you.
P.S.: A fourth option would be to implement a more sophisticated protocol where the server keeps track of changes to the list (additions/deletes) and the client can e.g. query for changes based on a version identifier or simply a timestamp. However I like the third option better as implementation-wise it is much more simpler and less error-prone on both client and server.
There is nothing in HTTP that says that POST must update the server. People seem to forget the following line in RFC2616 regarding one use of POST:
Providing a block of data, such as the result of submitting a
form, to a data-handling process;
There is nothing wrong with taking your client side wishlist and POSTing to a resource whose sole purpose is to return a set of differences.
POST /Bookstore/WishlistComparisonEngine
The whole concept behind REST is that you leverage the power of the underlying HTTP protocol.
In this case there are two HTTP headers that can help you find out if the list on your mobile device is stale. An added benefit is that the client on your mobile device probably supports these headers natively, which means you won't have to add any client side code to implement them!
If-Modified-Since: check to see if the server's copy has been updated since your client first retrieved it
Etag: check to see if a unique identifier for your client's local copy matches that which is on the server. An easy way to generate the unique string required for ETags on your server is to just hash the service's text output using MD5.
You might try reading Mark Nottingham's excellent HTTP caching tutorial for information on how these headers work.
If you are using Rails 2.2 or greater, there is built in support for these headers.
Django 1.1 supports conditional view processing.
And this MIX video shows how to implement with ASP.Net MVC.
I think the key problems here are the definitions of Book and Wishlist, and where the authoritative copies of Wishlists are kept.
I'd attack the problem this way. First you have Books, which are keyed by ISBN number and have all the metadata describing the book (title, authors, description, publication date, pages, etc.) Then you have Wishlists, which are merely lists of ISBN numbers. You'll also have Customer and other resources.
You could name Book resources something like:
/book/{isbn}
and Wishlist resources:
/customer/{customer}/wishlist
assuming you have one wishlist per customer.
The authoritative Wishlists are on the server, and the client has a local cached copy. Likewise the authoritative Books are on the server, and the client has cached copies.
The Book representation could be, say, an XML document with the metadata. The Wishlist representation would be a list of Book resource names (and perhaps snippets of metadata). The Atom and RSS formats seem good fits for Wishlist representations.
So your client-server synchronization would go like this:
GET /customer/{customer}/wishlist
for ( each Book resource name /book/{isbn} in the wishlist )
GET /book/{isbn}
This is fully RESTful, and lets the client later on do PUT (to update a Wishlist) and DELETE (to delete it).
This synchronization would be pretty efficient on a wired connection, but since you're on a mobile you need to be more careful. As #marshally points out, HTTP 1.1 has a lot of optimization features. Do read that HTTP caching tutorial, and be sure to have your web server properly set Expires headers, ETags, etc. Then make sure the client has an HTTP cache. If your app were browser-based, you could leverage the browser cache. If you're rolling your own app, and can't find a caching library to use, you can write a really basic HTTP 1.1 cache that stores the returned representations in a database or in the file system. The cache entries would be indexed by resource names, and hold the expiration dates, entity tag numbers, etc. This cache might take a couple days or a week or two to write, but it is a general solution to your synchronization problems.
You can also consider using GZIP compression on the responses, as this cuts down the sizes by maybe 60%. All major browsers and servers support it, and there are client libraries you can use if your programming language doesn't already (Java has GzipInputStream, for instance).
If I strip out the domain-specific details from your question, here's what I get:
In your RESTful client-server application, the client stores a local copy of a large resource. Periodically, the client needs to check with the server to determine whether its copy of the resource is up-to-date.
marshally's suggestion is to use HTTP caching, which IMO is a good approach provided it can be done within your app's constraints (e.g., authentication system).
The downside is that if the resource is stale in any way, you'll be downloading the entire list, which sounds like it's not feasible in your situation.
Instead, how about re-evaluating the need to keep a local copy of the Wishlist in the first place:
How is your client currently using the local Wishlist?
If you had to, how would you replace the local copy with data fetched from the server?
What have you done to minimize your client's data requirements when building its Wishlist view(s) and executing business logic?
Your third alternative sounds nice, but I agree that it doesn't feel to RESTfull ...
Here's another suggestion that may or may not work: If you keep a version history of of your list, you could ask for updates since a specific version. This feels more like something that can be a GET operation. The version identifiers could either be simple version numbers (like in e.g. svn), or if you want to support branching or other non-linear history they could be some kind of checksums (like in e.g. monotone).
Disclaimer: I'm not an expert on REST philosophy or implementation by any means.
Edit: Did you ad that PS after I loaded the question? Or did I simply not read your question all the way through before writing an answer? Sorry. I still think the versioning might be a good idea, though.