Search code examples
angular-universal

Angular Universal build a RESTful API


When creating a new Angular Universal app, a server.ts file is generated to handle the server-side rendering (SSR) process. If you need to make a server request to execute a backend function, it seems that you have to build a RESTful API using the adopted server framework Express.js as those two examples here and here describe. However, both examples are older than four years.

To execute backend functions, do I need to extend the generated server.ts file as described in the aforementioned links? Alternatively, does Angular Universal offer a different approach or pattern? Something compare to angular component or service, where I can also run the backend function within this service.

I understand that there needs to be an implementation of an http request, where the Express server listens for it. However, I expected that Angular Universal provides an additional layer to simplify this process.

server.ts file generated by angular universal:

import 'zone.js/node';

import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import { AppServerModule } from './src/main.server';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/antiquetrade-ssr/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  return server;
}

function run(): void {
  const port = process.env['PORT'] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

Solution

  • Angular is not such a frame work where you can run any back ground service. Angular universal is mainly responsible for rendering the app on the server. In your server.ts file you can see this following lines

    // Example Express Rest API endpoints
    // server.get('/api/**', (req, res) => { });
    

    Here, you can follow the regular express framework patterns in order to run tasks on server if needed. Overall, angular universal is not like other ssr frame works such as laravel. It's just binding angular to an express server in order to render the angular app on the server.