In my company, we're using Spring Boot to implement backend API and React to implement frontend including Web interface and Android/iOS apps.
Since our product is an Enterprise software, customers actually have to pay to get the latest backend API to deploy on their own servers. However, our mobile apps are regularly updated on the App Store. This leads to a situation where the mobile apps on end-users' devices may be the newer version while the backend API on the customer's machine is the older one. We plan to support up to 3 minor version backward, meaning FE 5.4 will support up to backend 5.2.
The backend does have an endpoint to return the current version number. However, I'm a bit clueless as to how our frontend implementation can maintain backward compatibility with older API versions as we add new features and may introduce breaking changes in backend API.
I completely understand there might not any beautiful solutions for this problem. I'm hoping if you've gone through this pain, you can share your experiences about what you've tried, the final approach that you took and the potential pitfalls to look out for.
I'm sure myself and other people who's running into this issue would be really grateful :).
Your solution will be similar to any frontend solution that uses Feature Toggle but I can already imagine that it will not be pretty.
Basically inside your code you'll have a lot of if/else statements or some form of wrapper that does the same underneath for every piece of UI/logic/functionality that is a breaking change on version upgrade.
I'd suggest that for every layers that you have (UI, logic, API call) you should start to have switches based on version returned by backend. You'll end up with a lot of redundant looking codes and a lot of codes that looks like this. (if you support only two versions. Use switch if you have more versions)
render() {
{version === "1.0.0" ? <VersionA /> : <VersionB/>}
}
You can however, write a utility method that wraps and returns different components based on versions. By doing that you can more easily remove components that you no longer need to support in the future.
const versionSwitcher = (version, ...Components) => {
switch (version) {
case "1.0.0":
return Components[0];
case "1.1.0":
return Components[1];
}
}
This of course, increases complexity throughout all layers but given your case I can't see it being simple. A good thing to do is to try to keep your own viewModel and never pass response from API directly into component. That reduces the coupling between API and your components and will make this a little easier.
Related
I've searched and searched and can't seem to find a pattern for this. I'd consider myself an intermediate Vue dev, however, the backend is my strong suit. I'm working on an app that will be white-labeled by resellers. While it's possible to have multiple builds, avoiding that would be ideal. The setup is a stand-alone vue-cli SPA connecting to a Laravel api backend and using the Sanctum auth package. So I need calls to the same domain. The issue: resellers will be on their own domain. The ask: Is there a pattern/solution for dynamically loading configs (mainly baseURL) for different domains (other items would by theme/stylesheet). Currently I have a few typical entries:
i.e. axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL
Basically, based on the domain the site is being served on, I'd like a dynamic/runtime config. I feel like this has been solved, but I can't seem to use the right search terms for some direction, so anything is helpful. I've tried a few things:
1) Parsing in js, but can't seem to get it to run early enough in the process to take effect? It seems to work, but I can't get it to "click"
2) Hit a public API endpoint with the current domain and get the config. Again, can implement, but can't seem to get it to inject into the Vue side correctly?
Any resources, pattern references or general guidance would be much appreciative to avoid maintaining multiple builds merely for a few variables. That said, I don't think there's much overhead in any of this, but also open to telling my I'm wrong and need multiple builds.
End Result
url visited is https://mydomaincom
then baseURL = https://api.mydomiancom
url visited https://resellerdomaincom
then baseURL=https://api.resellerdomaincom
I don't think there is a common pattern to solve your problem - I haven't found anything on the net.
The best software design solution could be the following:
have a single back-end
distribute only the client to your customers/resellers
Obviously the back end could see the domain of the application from which the request comes and manage the logic accordingly.
Good luck with your project.
Honestly how the question is put it's not really clear to me. Although my usual pattern is to:
Create an axios instance like so:
export const axiosInstance = axios.create({
// ...configs
baseURL: process.env.VUE_APP_URL_YOU_WOULD_LIKE_TO_HIT
})
and then whenever I make a request to some api, I would use this instance.
EDIT: According to your edit, you can either release the client to each customer, and have a .env file for each and every of them, or you can have a gateway system, where the client axios end point is always the same, hitting always the same server, and then from there the server decides what to ping, based on your own logic
I'm trying to write a new language detector plugin for i18next for integration with hapi. There's an existing hapi-i18next plugin that is quite old (it uses an extemely old version of i18next, 1.7.10 ) and so mostly useless. And the i18next API docs are pretty vague about how to write new plugins and exactly what the language detection process is. Does it run every time the t() function runs? should it be asynchronous? Has anybody else out there recently integrated hapi with i18next? I realize this is rather general but i'm not sure where else to turn.
Never used hapi so far, but seems hapi evolved a lot since version 8 (what's actually used here)
I don't know if that project is still maintained...
Perhaps you could try to create a new hapi-i18next plugin... (was not that much code)
To create a languageDetector plugin, it should not be a big thing... start here and continue by comparing how the express language detection works
In i18next the languageDetector is triggered here
...so on init/load and on a potential language change
I hope this helps.
What I ended up doing is writing a hapi server extension rather than a plugin, and a module that runs at startup that decorates the hapi server object with the initialized i18next object. The extension is installed to run onPreHandler and it basically clones the i18next object, attaches that instance to the request object, and detects the language (from the request header or from a query parameter), then sets the cloned instance to that language. This way, whenever a route handler uses the t() function attached to the instance that's attached to the current request, we know we'll be translating into the right language. Note that this is still for Hapi 16 (I need to port to 17/18 soon)...
I'm using the latest ASP.Net WebAPI Nightly builds (dated 2013-01-16).
I have a simple EF database first model at the moment that has two entities - Patients and Visits. Each patient can have many visits.
I'd like to be able to query for my list of patients and have the visits entities for each patient returned inline. I know that WebAPI's OData implementation doesn't yet support $expand. I'm hoping that just means that optional client-controlled expansion is not supported and that I can force expansion server-side.
At the moment I'm not getting any of the visits inline.
For example, my PatientController's() Get() method looks like
[Queryable(AllowedQueryOptions=AllowedQueryOptions.Supported)]
public override IQueryable<Patient> Get()
{
var query = this.entities.Patients.Include("Visits");
return query;
}
I've verified that the query executing against my database does indeed include the visit information.
To use a publicly available OData service as an example, if you use the service at http://services.odata.org/OData/OData.svc/, you can get a list of Suppliers. This is http://http://services.odata.org/OData/OData.svc/Suppliers.
You can also ask for a list of suppliers that includes the list of products using http://http://services.odata.org/OData/OData.svc/Suppliers?$expand=Products
Stepping through the ASP.NET code (via the symbols server) I've got to the System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer and can see that it's CreatePropertyBag method, which builds up the list of properties to be serialized, just doesn't include the navigation properties, and they don't seem to be enumerated anywhere else apart from being written out as NavigationLinks.
I'm quite new to the ASP.NET world in general and have spent a week or so getting my head around the way things work (particularly with the changes made to OData at the end of 2012 and further changes made so far in 2013).
I suspect that if the ODataEntityTypeSerializer was to be modified (I'm happy to try) to embed this extra information in the appropriate spot (within each navigation link as an nested inline feed as best I can tell) then I'd be set.
Questions:
Have I overlooked something obvious and there's a flag I can set to turn on this behaviour? I can see why, if such a flag exists, it would be off by default (EF lazy loading and this flag wouldn't get on well)
If #1 is no, is there some other ODataEntityTypeSerializer that I could use? If so, how do I switch to it?
If #2 is no, any pointers for where I should start writing my own? Is there a place I can substitute in my own serializer or do I have to maintain my own fork of ASP.NET's Extensions project (as opposed to the Runtime project)
Thanks very much!
$expand is very high on our list of things to support for OData. But as far as I know, we don't have any flag to turn it on server-side. The formatter doesn't currently allow you to substitute your own serializers either. So I'm afraid your only option in the meantime is to create a fork and add support for $expand. If you manage to get it working, please consider sending a pull request our way:
http://aspnetwebstack.codeplex.com/SourceControl/network
You can try it already in webapi nightly builds.
Here is how to install it with nuget:
http://aspnetwebstack.codeplex.com/wikipage?title=Use%20Nightly%20Builds
I am currently working on a ASP.NET MVC 3 project and I am setting up the solution file on VS2010.
I am not sure of what is the standard approach. I am using the following approach
Company.Dept.Data (contains the dbml file - Data Model)
Company.Dept.Business (Business logics)
Company.Dept.Web (contains ASP.NET MVC3 webapplication)
The first two are class libraries and the last one is MVC3 web application.
Anyother recommendations?
There is no single "standard" approach. It all depends on your project and what problems you are trying to solve with the software. Your proposed structure of having 2 class libraries and 1 web project is one way to go for sure.
If you are going to do any kind of Dependency Injection using an Inversion of Control container, you might also want to consider having an "API" project for interfaces and an "Impl(ementation)" project for concrete classes that fulfill the interface contracts.
To echo danludwig, there really is no standard. I prefer breaking up libraries and namespaces according to functionality. Company.Db is my library for interacting with the database, Company.Mail are my wrappers around the Postmark mail service, etc.
I then tend to group like libraries into single repositories. So the 'storage' repository in source control holds Company.Db, Company.Caching, Company.FileStorage, etc. I have another repository 'messaging' that holds Company.Mail and Company.SMS (for interacting with Twilio to send text messages). When I branch out with new apps or new services (maybe a WCF endpoint for mobile clients), I can just pull down the 'messaging' repository, and I have all my class libraries for communicating with the user.
An application then looks like
Company.Application.Webite
\Libraries\Messaging
\Libraries\Messaging\Company.Mail
\Libraries\Storage
\Libraries\Messaging\Company.Db
\Libraries\Messaging\Company.Caching
\Libraries\Web
...
Company.Application.Wcf
\Libraries\Messaging
\Libraries\Storage
\Libraries\Messaging\Company.Db
\Libraries\Messaging\Company.Caching
...
This way, whether someone registers via the site, or via the mobile app, Company.Mail.MailServices.SendWelcomeEmail() sends the exact same welcome email, and there's no code duplication.
Whether this works for you, or even makes sense, who knows. I've also changed this scheme a hundred times, trying to find a layout that works with my development style/workflow. I wouldn't worry or stress too much about it, because whatever you pick, you're going to find things you like about it, and you'll find things you hate about it. I sometimes fall into the trap of spending more time trying to make everything "perfect", than to just code and change things I don't like.
What is the best approach to version WebAPIs?
I am building an API from scratch and I would like to ensure that it will version gracefully in the future. I am envisioning something like mysite.com/api/v2/...
One approach I see is to create a separate project (web app) for each version of API. But perhaps there are better ways to do it?
Thank you for your ideas.
Including version number in the URL is the standard approach as I explained in this post (I do not repeat the content): Implementing versioning a RESTful API with WCF or ASP.Net Web Api
You do not need to create a completely new project although you can. The problem that you will be facing with a single project is that there will be collision of names:
/api/v1.0/Car/123
and
/api/v2.0/Car/123
both will point to CarController while you can have only one of those. The solution would be to implement your own IHttpControllerSelector and register with the DependencyResolver. This implementation will look at the version number and perhaps find the type based on the namespace.
UPDATE
I do not intend to start a REST controversy here. But as #DarrelMiller points out, here is an older discussion on the same subject discouraging my suggested approach:
How to version REST URIs
I personally think URL versioning is the way to go.
You will need to create your own implementation of IHttpControllerSelector. The best way is to base this implementation on Microsoft's IHttpControllerSelector. Then you can decide in your IHttpControllerSelectorif you want to version by URL or by content-type.
The most basic implementation directly implements IHttpControllerSelector and just implements the SelectController method but performance reasons it is better to implement some caching around it.
For finding the Controller you simple the IHttpControllerTypeResolver instance you can get using HttpConfiguration.Services.
I've used something like this: http://damsteen.nl/blog/implementing-versioning-in-asp.net-web-api. Also put some code on Github: https://github.com/Sebazzz/SDammann.WebApi.Versioning.