How do multiple versions of a REST API share the same data model? - api

There is a ton of documentation on academic theory and best practices on how to manage versioning for RESTful Web Services, however I have not seen much discussion on how multiple REST APIs interact with data.
I'd like to see various architectural strategies or documentation on how to handle hosting multiple versions of your app that rely on the same data pool.
For instance, suppose you make a database level destructive change to a database table that causes you to have to increment your major API version to v2.
Now at any given time, users could be interacting with the v1 web service and the v2 web service at the same time and creating data that is visible and editable by both services. How should this be handled?

Most of changes introduced to API affect the content of the response, till changes introduced are incremental this is not a very big problem (note: you should never expose the exact DB model directly to the clients).
When you make a destructive/significant change to DB model and new API version of API is introduced, there are two options:
Turn the previous version off, filter out all queries to reply with 301 and new location.
If 1. is impossible to need to maintain both previous and current version of the API. Since this might time and money consuming it should be done only for some time and finally previous version should be turned off.
What with DB model? When two versions of API are active at the same time I'd try to keep the DB model as consistent as possible - having in mind that running two versions at the same time is just temporary. But as I wrote earlier, DB model should never be exposed directly to the clients - this may help you to avoid a lot of problems.

I have given this a little thought...
One solution may be this:
Just because the v1 API should not change, it doesn't mean the underlying implementation cannot change. You can modify the v1 implementation code to set a default value, omit the saving of a field, return an unchecked exception, or do some kind of computational logic that helps the v1 API to be compatible with the shared datasource. Then, implement a better, cleaner, more idealistic implementation in v2.

when you are going to change any thing in your API structure that can change the response, you most increase you'r API Version.
for example you have this request and response:
request post: a, b, c, d
res: {a,b,c+d}
and your are going to add 'e' in your response fetched from database.
if you don't have any change based on 'e' in current client versions, you can add it on your current API version.
but if you'r new changes are going to change last responses, for example:
res: {a+e, b, c+d}
you most increase API number to prevent crashing.
changing in the request input's are the same.

Related

Bulk POST request without enumerating objects

I'm trying to let my API clients make a POST request that bulk modifies objects that the client doesn't have their IDs.
I'm thinking of implementing this design but I don't feel good about it, are there any better solutions than this?
POST url/objects/modify?name=foo
This request will modify all objects with the name foo
This can be a tricky thing to do with an API because it doesn't age very well.
By that I mean that over time, you might introduce more criteria for the data stored on resources (e.g., you can only set this field to "archived" if the create_time field is older than 6 months). When that happens, your bulk updates will start to only work on some resources and now you have to communicate that back to the person calling the API.
For example, for any failures you need to explain that the update worked for some resources (and list them out) but failed on others (and list them out) and the reason why for each failure (and remember you might have different failure conditions for different resources).
If you're set on going down this path, the closest thing I can think of is the "criteria-based delete" method shown here: https://google.aip.dev/165.

Forward compatiblity in GraphQL

GraphQL is well-known for its easy to maintain backward-compatibility of APIs defined with it. You're supposed to just add new fields/types every time you need them and never remove old ones, only mark them with #deprecated directive. Thus, your server could evolve independently of its clients versions.
However, I have a quite opposite problem: we have many independent servers, some of which could not be updated ever, and client (potentially) could connect to anyone of them. Thus, when client adopts new fields in API types, that were introduced in some newer server, and then it connects to the older one, it will get the error, because it will try to query fields that do not exist on that server.
So the question is: is there some known approach on how to handle this type of situation in GraphQL?
The only thing I came up with is to have a top-level query field, that will return a list of supported types, as a string list. Thus, whenever you want to add a new filed in the existing type foo, you just add a new type foo2 and add this type to the list of supported types. Thus the client could decide what types it can use and, accordingly, what features it could show. However, this looks quite scary due to, well, graph nature of GraphQL: it is very hard to guaranty that clinet's query won't get to some unsupported type via some quirky path.
The other solution is, of course, just version the whole API and treat any change to schema as incompatible API version. But this looks, well, either too stiff, or too laborious to maintain.
P.S. I suppose, that, maybe GraphQL is just not a good solution for this type of situations, but, as usually happens, we decided to go with GraphQL far before we could foresee these use-cases.
... usually there is no state with 'could not be updated ever' servers
How it wouldn't affect REST servers? Just responds with 404 for /api/Vxxx - clearly not supported new version? Better DX than with graphQL? I don't think so.
Possible solutions:
provide APIs with some query version (+loadable schema) - ask devs to use at app beginning (with login query);
add 'field introduced in API version xxx' in docs;
keep a list of servers with supported API versions;
some service/server queryable for [nearest] server with minimum API version xxx.

How to organize endpoints when using FeathersJS's seemingly restrictive api methods?

I'm trying to figure out if FeathersJS suits my needs. I have looked at several examples and use cases. FeathersJS uses a set of request methods : find, get, create, update, patch and delete. No other methods let alone custom methods can be implemented and used, as confirmed on this other SO post..
Let's imagine this application where users can save their app settings. Careless of following method conventions, I would create an endpoint describing the action that is performed by the user. In this case, we could have, for instance: /saveSettings. Knowing there won't be any setting-finding, -creation, -updating (only some -patching) or -deleting. I might also need a /getSettings route.
My question is: can every action be reduced down to these request methods? To me, these actions are strongly bound to a specific collection/model. Sometimes, we need to create actions that are not bound to a single collection and could potentially interact with more than one collection/model.
For this example, I'm guessing it would be translated in FeathersJS with a service named Setting which would hold two methods: get() and a patch().
If that is the correct approach, it looks to me as if this solution is more server-oriented than client-oriented in the sense that we have to know, client-side, what underlying collection is going to get changed or affected. It feels like we are losing some level of freedom by not having some kind of routing between endpoints and services (like we have in vanilla ExpressJS).
Here's another example: I have a game character that can skill-up. When the user decides to skill-up a particular skill, a request is sent to the server. This endpoint can look like POST: /skillUp What would it be in FeathersJS? by implementing SkillUpService#create?
I hope you get the issue I'm trying to highlight here. Do you have some ideas to share or recommendations on how to organize the API in this particular framework?
I'm not an expert of featherJs, but if you build your database and models with a good logic,
these methods are all you need :
for the settings example, saveSettings corresponds to setting.patch({options}) so to the route settings/:id?options (method PATCH) since the user already has some default settings (created whith the user). getSetting would correspond to setting.find(query)
To create the user AND the settings, I guess you have a method to call setting.create({defaultOptions}) when the user CREATE route is called. This would be the right way.
for the skillUp route, depends on the conception of your database, but I guess it would be something like a table that gives you the level/skills/character, so you need a service for this specific table and to call skillLevel.patch({character, level})
In addition to the correct answer that #gui3 has already given, it is probably worth pointing out that Feathers is intentionally restricting in order to help you create RESTful APIs which focus on resources (data) and a known set of methods you can execute on them.
Aside from the answer you linked, this is also explained in more detail in the FAQ and an introduction to REST API design and why Feathers does what it does can be found in this article: Design patterns for modern web APIs. These are best practises that helped scale the internet (specifically the HTTP protocol) to what it is today and can work really well for creating APIs. If you still want to use the routes you are suggesting (which a not RESTful) then Feathers is not the right tool for the job.
One strategy you may want to consider is using a request parameter in a POST body such as { "action": "type" } and use a switch statement to conditionally perform the desired action. An example of this strategy is discussed in this tutorial.

Change Key of HttpContext.Request.Query item in ASP.NET Core

I am trying to work around a issue with a 3rd party filter. My current plan is to put a filter in front of that filter to "fix" the query string so it does not error out.
I made an ActionFilterAttribute and added it into the filter list. It is running fine. I am adding my logic in the OnActionExecuting method.
The first item of context.HttpContext.Request.Query has a Key that is a json structure. I need to change that Key to be {}.
Problem is that both context.HttpContext.Request.Query and context.HttpContext.Request.QueryString are read-only.
How can I alter the context.HttpContext.Request.Query or the context.HttpContext.Request.QueryString?
EDIT - The Underlying Problem:
BreezeJS did a minimal level upgrade to support .NET Core. In this upgrade, part of the code expects that every call that has any parameters to return an IQueryable (QueryFns.cs Line 32). From reading the code it seems like this is an error (the calling function (the actual filter) seems to just expect null to be returned not an Exception.)
Either way, this makes moving to .NET Core very hard.
I considered my other options and if this fails, I will continue to pursue them:
Submit a pull request to fix the issue: The project has not accepted any pull requests in over a year and a half. So it seems unlikely my request will be taken.
Fork my own branch: I would rather not have to create and maintain a separate version with my own build and publishing pipeline.
Find a way to make the Breeze filter ignore the call when the result is not an IQueryable: I am currently looking into this one. (This question.)
Find a way to send my call from the client differently so that breeze ignores calls that do not return IQueryable: The return type of the call is owned by the service. And this is an issue with the service. I would rather not have to have tight coupling between the service and the client such that the client is crafting workarounds for service filter issues.

How to keep GraphQL API and frontend synchronized on a staging server?

We have a Rails application with GraphQL API in one GIT repository, and React frontend application in another. Both backend and frontend have CI and are deployed separately. But both backend and frontend are still under heavy development and often our staging server doesn't work, because deployment is not synchronized and we don't test the whole application - we test API and we test frontend without API.
What is the best way to deploy frontend and backend only when they are synchronized, I mean when new versions doesn't break functionalities? I thought about third repository with backend and frontend included as GIT modules, acceptance tests and deploying both sides at once. But maybe there is simpler solution? Maybe some versioning?
You certainly can do versioning with GraphQL, but ideally any changes to your schema shouldn't be breaking ones. This just takes discipline on the part of your backend devs, although there are also tools (like this) to help detect breaking changes. Some general guidelines:
Deprecate fields using the #deprecated directive instead of deleting them. Deprecated fields can be communicated to client teams and retired after some agreed-upon amount of time.
Avoid renaming types. Try to use more specific naming to avoid having to rename things in the future (i.e. use emailMessage instead of just message if you could foreseeably have a different kind of message in the future).
Use payload types for mutations. If you mutate a User, for example, instead of just returning the User, return a payload type that has a user field. If down the road, you realize the mutation should also return other information, you can easily add fields to the payload type without creating breaking changes.