Design of an isomorphic App
In a typical single-page application (SPA) server sends JSON data. Browser receives that JSON data and builds HTML.
In an isomorphic app, the server sends a fully-formed HTML to the browser. This is typically done for SEO, performance and code maintainability.
In an isomorphic app the browser does not directly deal with the API server. This is because the API server will render JSON data and browser needs to have fully formed HTML. To solve this problem a "proxy server" is introduced in between the browser and the API server.
In this case the proxy server is powered by Node.js.
Uploading a file in an isomorphic app
Recently, while working on an isomorphic app, we needed to upload a file to the API server. We couldn't directly upload from the browser because we ran into CORS issue.
One way to solve CORS issue is to add CORS support to the API sever. Since we did not have access to the API server this was not an option. It means now the file must go through the proxy server.
The problem can be seen as two separate issues.
- Uploading the file from the browser to the proxy server.
- Uploading the file from the proxy server to the API server.
Implementation
Before we start writing any code, we need to accept file on proxy server and it can be done by using Multer.
Multer is a node.js middleware for handling multipart/form-data.
We need to initialize multer with a path where it will store the uploaded files.
We can do that by adding the following code before initializing the node.js server app.
1app 2 .set("config", config) 3 // ...other middleware 4 .use(multer({ dest: "uploads/" }).any()); // add this line
Now any file uploaded to proxy server would be stored in the /uploads directory.
Next we need a function which uploads a file from browser to the node.js server.
1// code on client 2 3function uploadImagesToNodeServer(files) { 4 const formData = new FormData(); 5 map(files, (file, fileName) => { 6 if (file && file instanceof File) { 7 formData.append(fileName, file); 8 } 9 }); 10 11 superagent 12 .post("/node_server/upload_path") 13 .type("form") 14 .set(headers) 15 .send(data, formData) 16 .then((response) => { 17 // handle response 18 }); 19}
Next, let's upload the same file from the node.js server to the API server.
To do that, we need to add a callback function to our node.js server where we are accepting the POST request for step 1.
1// code on node.js server 2app.post("/node_server/upload_path", function (req, res) { 3 uploadImagesToApiServer(req); 4 // handle response 5}); 6 7function uploadImagesToApiServer(req) { 8 superagent 9 .post("/api_server/upload_path") 10 .type("form") 11 .set(headers) 12 .attach("image", req.files[0].path) 13 .then((response) => { 14 // handle response 15 }); 16}