Using ABP 3.2.1 in a microservices architecture with Angular front-end.
We have several microservices (lets call them Accounting, Customer and Order), each with a controller with an Area attribute(module name) and RemoteService named as per the microservice name.
Using the Abp CLI, we are attempting to generate proxies for each of these services individually.
A snippet of our environment.ts file:
apis: {
default: {
rootNamespace: "Example",
url: 'https://localhost:5000',
},
Accounting: {
rootNamespace: "Example",
url: 'https://localhost:5010',
},
Customer: {
rootNamespace: "Example",
url: 'https://localhost:5011',
},
Order: {
rootNamespace: "Example",
url: 'http://localhost:5012',
}
When running generate-proxy for the first time, it works fine. E.g abp generate-proxy --module order --api-name Order.
However when running this for the second time against a different API (E.g, abp generate-proxy --module accounting --api-name Accounting, it fails with an error saying:
[Invalid Module] Backend module "order" does not exist in API definition - however when this errors we are actually attempting to target the "accounting" module.
The behaviour here seems to be that it's expecting any previously generated modules to exist in all target API's.
Has anyone got this to work successfully? Any suggested workarounds?
The issue here is; You don't have separate Angular modules but you have separate back-end modules for your front-end. This makes the back-end and front-end API usage incompatible.
abp generate-proxy generates all modules because there's a potential sharing of common DTOs or objects between different modules. So the best practise is BFF Backends For Frontends pattern.
Hence the answer is; Create Order and Accounting Angular modules.
See;
https://learn.microsoft.com/en-us/azure/architecture/patterns/backends-for-frontends
https://nordicapis.com/building-a-backend-for-frontend-shim-for-your-microservices/
Related
I'm working on a larger React Application right now and have some questions about if I set everything up correct (Best Practice). The application has two different "sections". I'm trying to give an easier example (school scenario) how the structure is set up:
The first section of the application is used by principal to set up school classes, teachers, students, rooms, etc...
The section section is used by all the users (teachers, students) that the principal defined. The teachers can set up timetables, etc...
Now what I trying to is: The principal can access his section of the application with the url: admin.school.com - The teachers and students can access the application with the url: school.com
I've put everything in a single react application right now, so I can use the same design, components, etc. During development I switch between the two applications by comment out the application I don't want to access in the index.js file:
// ReactDOM.render(<AppAdmin />, document.getElementById('root'));
ReactDOM.render(<App />, document.getElementById('root'));
My question now is: (How) is it possible that I can get a Build of the application with two "index.html" files so "admin.school.com" points to "admin.html" and "school.com" points to "index.html". My main goal is (like I said) - to have one code basis on my server and just two different html files. Is this possible or do I need to build the application twice? The principal should be able to access the normal section without new login.
I hope that my explanation was easy to understand. Thank you for your help!
You can use process.env to pass environment variables (see https://create-react-app.dev/docs/adding-custom-environment-variables/ if using create-react-app), e.g. in index.js:
const Component = process.env.REACT_APP_ADMIN ? AppAdmin : App
ReactDOM.render(<Component />, ...)
and in package.json:
"scripts": {
...
"build-admin": "REACT_APP_ADMIN=1 npm run build"
}
You can split React application into several Single Page Applications (SPAs). Crisp React boilerplate supports this functionality. Although it uses TypeScript.
My question now is: (How) is it possible that I can get a Build of the application with two "index.html" files.
The two .html files can be called differently.
You can have one SPA called admin with the entry point (also called landing page) admin.html. And another SPA called school with entry point school.html. All you need for that is to modify the SPA Configuration block:
var SPAs = [
new SPA({
name: "admin",
entryPoint: "./src/entrypoints/first.tsx",
redirect: false
}),
new SPA({
name: "school",
entryPoint: "./src/entrypoints/second.tsx",
redirect: true
})
];
SPAs.appTitle = "SchoolApp";
and execute yarn build. Both SPAs are created for you with .html files. Of course you can write admin.tsx, school.tsx and use it instead of first.tsx, second.tsx.
so "admin.school.com" points to "admin.html" and "school.com" points to "index.html".
This is a non-React part.
You create two DNS entries for "admin.school.com" and "school.com", both pointing to the same IP address of your webserver. Let's assume you use NodeJS/Express. In its route handler for / e.g. app.get("/", (req, res, next) => { ... } examine req.hostname and depending on it being either "admin.school.com" or "school.com" make the handler serve admin.html or school.html.
I've split my react application in 3 different projects, using CRA for all of them, auth, X and Y. User is first sent to auth, then I redirect him to either X or Y based on some info.
It works perfectly on PRODUCTION environment (because they run on the same domain), but on dev, X and Y failed to authenticate the user, because they run on different ports (different domains) the data in local storage is not shared between auth, X and Y.
I've tried to find a way to use a reverse proxy (http-proxy) to host the React dev servers on the same domain, but failed too, because the services could not find the assets/static folder, resulting in 404. Also tried http-proxy-middleware, as it is recommended on the CRA docs page, but failed to do so. Is there an easier way that I'm not seeing?
Edit: Found something new, but also failed. Used react-rewired to override CRA scripts, to use PUBLIC_PATH on DEV, but now my bundle.js returns an index.html file.
The following code does redirect to the accordingly react project, but the assets are requested to the wrong path.
const apiProxy = httpProxy.createProxyServer();
app.all("/login/*", function(req, res) {
console.log('redirecting to Login');
apiProxy.web(req, res, {target: servers.login});
});
app.all("/implementacao/*", function(req, res) {
console.log('redirecting to Implementation');
apiProxy.web(req, res, {target: servers.implementation});
});
So I used react-rewired to change the public path
const {
override,
} = require('customize-cra');
module.exports = {
webpack: override(
(config) => {
config.output.publicPath = '/login/';
return config;
},
),
jest: config => {
return config;
},
devServer: configFunction => (proxy, allowedHost) => {
return configFunction(proxy, allowedHost);
},
paths: (paths, env) => {
return paths;
}
};
Now, the assets requests are made correctly to /login/, but nothing the dev server always return an index.html file.
Even with react-app-rewired, to override config, and use publicPath on dev, the assets will not be served from the publicPath.
There is already a pull request on CRA to use PUBLIC_URL in dev mode.
Is there an easier way that I'm not seeing?
Another approach would be to use multiple React Single Page Applications (SPAs) inside one application, see crisp-react. E.g. instead of 3 CRAs in 3 applications/projects have 3 SPAs in one application/project. The backend surely can get data from other backend servers transparently for each SPA.
how do I migrate from a set of existing CRA projects to using crisp-react ?
Background
crisp-react comes with two stock SPAs called ‘First’ and ‘Second’. Both render some explanatory/sample UI.
Migration overview
1.Pick one CRA project and migrate it to the ‘First’ SPA. When finished, you have two CRAs left and two crisp-react SPAs: ‘First’ (renders your UI) and ‘Second’ (still renders the sample UI). Rename the ‘First’ SPA to give it more meaningful name.
2. Pick another CRA and migrate it. When finished, you have one CRA left and two crisp-react SPAs both rendering your UI.
3.Modify crisp-react to add the third SPA and then migrate the remaining CRA to the third SPA.
Migration steps (sketch)
1.1 Follow crisp-react Getting Started.
1.2 The landing page of the First SPA is rendered by crisp-react/client/src/entrypoints/first.tsx
The landing page of the CRA is rendered by src/index.tsx
Replace the content of the former with the latter.
1.3 The first CRA consists of React components: src/App.tsx and others you added. Copy the components to crisp-react/client/src/components/from-first-cra/
1.4 Ensure crisp-react client app compiles: From crisp-react/client/ execute: yarn compile
1.5 Ensure crisp-react client app builds: From crisp-react/client/ execute: yarn build
1.6 Ensure crisp-react client looks ok without backend data: see client Usage Scenarios.
1.7 Get the backend (e.g. Express) involved: see backend Usage Scenarios.
1.8 Milestone reached: browser can be pointed to backend (Express) and get from it html files and bundles - which results in the first SPA rendering initial UI (to the extent possible without data supplied via API enpoints).
1.9 Decide how the the first SPA will get data from API. 3 basic choices here:
- the API endpoints are implemented in Express so you can retire your backend servers
- Express does expose API endpoints but acts as a reverse proxy getting data from your backend servers
- Express knows nothing about API and data supplied by backend servers that are queried directly by the components inside the first SPA.
2.1 Second SRA
as above
...
I am trying to do an external API call using the git project https://github.com/zuiidea/antd-admin. Even after trying for more that 2 weeks i couldn't able to figure it out. This package is using mock data which is giving the data feed for the sample pages. But i am going to use this package to build a separate web app for one of my project.
I tried to fetch one of the online json api from https://jsonplaceholder.typicode.com/ but i cant able to fetch the data. I still cant figure out where i need to call the api since it was using dva, umi framework
I need an example so that i can call the api from this package which will be helpful for me to complete my project.
In .umirc.js file you must declare proxy for app like below
proxy: {
'/api/v1/': {
target: 'https://jsonplaceholder.typicode.com/',
changeOrigin: true,
pathRewrite: { '^/api/v1/': '' },
},
},
After that you can test external API like this
curl -X GET http://localhost:<port>/api/v1/todos
I'm using the latest react SPA .NET Core 3 template and wondering is there a way to set the "AccessTokenLifetime" for a client, where obviously that client is my SPA.
I've been looking here https://github.com/aspnet/AspNetCore.Docs/blob/master/aspnetcore/security/authentication/identity-api-authorization.md#application-profiles and I've tried quite a few different things.
But doesn't seem there is a way to set client properties, other than the few detailed on the page above eg RedirectUri, LogoutUri
After a bit of hunting I found that you can do it during the call to AddApiAuthorization<ApplicationUser, ApplicationDbContext>(); in the Startup
Replace it with:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(opt =>
{
foreach (var c in opt.Clients)
c.AccessTokenLifetime = 120; // Expiration in Seconds
});
All of the Token settings for Identity Server seem to be settable here.
Note that the collection of Clients is determined by your configuration. In the case of the basic dotnet net react -o <name> -au Individual template, the following is in the appSettings.json using the name of the project (the -o option to the dotnet command):
"IdentityServer": {
"Clients": {
"ReactAppIdentity": {
"Profile": "IdentityServerSPA"
}
}
I dug around in the source code but unfortunately I couldn't see a way to set these settings via configuration.
I have a well working app writing with Requirejs and Backbonejs, but it's really slowing sometimes... For example when it comes to make some arithmetic work! I tried to use a Web Worker to do this arithmetic work like this :
My Module(traffic.js) :
define(["jquery", "use!underscore", "use!backbone", "namespace" ],
function ($, _, Backbone, globals) {
.....
var worker = new Worker("arithmetic.js");
worker.addEventListener('message', function(e) {
console.log(e.data);
}, false);
worker.postMessage(globals.data); // Send data to our worker.
});
arithmetic.js :
define(["use!underscore", "use!backbone" ],
function ($, _) {
//Here die Operations
});
But i have the Error define is not defined!!
I tried it like this too but no success!!
How to use Web Worker into requirejs or with backbonejs??
Thanks!
You can use requireJS from web workers: see the API docs for more info.
The only requirement is to load requireJS at the start of the web worker with importScripts(…). Once that is loaded, you can use define and use requireJS like normal.
The key part for me when I was getting it to work was to make sure that you are also loading the same bootstrap configuration (e.g. config.js or main.js) in the web worker that you are using in the rest of your app. This is what the doc is talking about when it says:
You will likely need to set the baseUrl configuration option to make sure require() can find the scripts to load.
Another thing is that you can load the worker from your traffic.js file with a module ID (instead of hardcoding the script path) utilizing this requireJS plugin.