The UI5 Server Extensibility enables you to enhance the functionality of the UI5 Server. You may want to handle requests differently. For example add various headers to a response or parse data of a POST request in a specific way. For this you can plug custom middleware implementations into the internal express server of the UI5 Server module.
The UI5 community already created many custom middleware packages which you can integrate into your project. They are often prefixed by ui5-middleware- to make them easily searchable in the npm registry.
Please note that custom middleware packages from third parties can not only modify how your project is served but also execute arbitrary code on your system. In fact, this is the case for all npm packages you install. Always act with the according care and follow best practices.
In a projects ui5.yaml file, you can define additional server middleware modules that will be executed when the request is received by the server. This configuration exclusively affects the server started in this project. Custom middleware configurations defined in any dependencies are ignored.
A middleware may be executed before or after any other middleware. This can either be a standard middleware or another custom middleware.
In the above example the middleware compression is already included as a standard middleware by the UI5 Server. When serving the application my.application, the server will call the custom middleware myCustomMiddleware after compression.
There can be optional configuration parameters which are passed directly to the custom middleware implementation (see below).
An optional mountPath for which the middleware function is invoked can be provided. It will be passed to the app.use call (see express API reference).
Note that middleware configurations are applied in the order they are defined. When referencing another custom middleware, it has to be defined before that reference.
A custom middleware extension consists of a ui5.yaml and a custom middleware implementation. It can be a standalone module or part of an existing UI5 project.
Custom middleware extensions can be standalone modules which are handled as dependencies.
Alternatively you can implement a custom middleware extension as part of your UI5 project. In that case, the configuration of the extension is part of your project configuration inside the ui5.yaml as shown below.
The UI5 Server will detect the custom middleware configuration of the project and use the middleware on startup.
Example: Custom Middleware Extension defined in UI5 project¶
# Project configuration for the above examplespecVersion:"3.0"kind:projecttype:applicationmetadata:name:my.applicationserver:customMiddleware:-name:markdownHandlerbeforeMiddleware:serveResources---# Custom middleware extension as part of your projectspecVersion:"3.0"kind:extensiontype:server-middlewaremetadata:name:markdownHandlermiddleware:path:lib/middleware/markdownHandler.js
/** * Custom UI5 Server middleware API * * @param {object} parameters Parameters * @param {@ui5/logger/Logger} parameters.log * Logger instance for use in the custom middleware. * This parameter is only provided to custom middleware * extensions defining Specification Version 3.0 and later. * @param {@ui5/server.middleware.MiddlewareUtil} parameters.middlewareUtil * Specification version-dependent interface to a * MiddlewareUtil instance. See the corresponding API reference for details: * https://sap.github.io/ui5-tooling/v3/api/@ui5_server_middleware_MiddlewareUtil.html * @param {object} parameters.options Options * @param {string} parameters.options.configuration * Custom middleware configuration, as defined in the project's ui5.yaml * @param {string} parameters.options.middlewareName * Name of the custom middleware. * This parameter is only provided to custom middleware extensions * defining Specification Version 3.0 and later * @param {object} parameters.resources Readers for accessing resources * @param {module:@ui5/fs.AbstractReader} parameters.resources.all * Reader to access resources of the root project and its dependencies * @param {module:@ui5/fs.AbstractReader} parameters.resources.rootProject * Reader to access resources of the root project * @param {module:@ui5/fs.AbstractReader} parameters.resources.dependencies * Reader to access resources of the project's dependencies. * @returns {function} Middleware function to use */exportdefaultfunction({log,middlewareUtil,options,resources}){returnasyncfunction(req,res,next){// [...]}};
/** * Custom UI5 Server middleware API * * @param {object} parameters Parameters * @param {@ui5/logger/Logger} parameters.log * Logger instance for use in the custom middleware. * This parameter is only provided to custom middleware * extensions defining Specification Version 3.0 and later. * @param {@ui5/server.middleware.MiddlewareUtil} parameters.middlewareUtil * Specification version-dependent interface to a * MiddlewareUtil instance. See the corresponding API reference for details: * https://sap.github.io/ui5-tooling/v3/api/@ui5_server_middleware_MiddlewareUtil.html * @param {object} parameters.options Options * @param {string} parameters.options.configuration * Custom middleware configuration, as defined in the project's ui5.yaml * @param {string} parameters.options.middlewareName * Name of the custom middleware. * This parameter is only provided to custom middleware extensions * defining Specification Version 3.0 and later * @param {object} parameters.resources Readers for accessing resources * @param {module:@ui5/fs.AbstractReader} parameters.resources.all * Reader to access resources of the root project and its dependencies * @param {module:@ui5/fs.AbstractReader} parameters.resources.rootProject * Reader to access resources of the root project * @param {module:@ui5/fs.AbstractReader} parameters.resources.dependencies * Reader to access resources of the project's dependencies. * @returns {function} Middleware function to use */module.exports=function({log,middlewareUtil,options,resources}){returnasyncfunction(req,res,next){// [...]}};
importMarkdownItfrom"markdown-it";exportdefaultasyncfunction({log,middlewareUtil,options,resources}){constmd=newMarkdownIt();returnfunction(req,res,next){if(!req.path||!req.path.endsWith(".html")){// Do not handle non-HTML requestsnext();return;}// Try to read a corresponding markdown fileresources.rootProject.byPath(req.path.replace(".html",".md")).then(async(resource)=>{if(!resource){// No file found, hand over to next middlewarenext();return;}log.info(`Rendering markdown for ${resource.getPath()}`);constmarkdown=awaitresource.getBuffer();// Generate HTML from markdown stringconsthtml=md.render(markdown.toString());res.type('.html');res.end(html);}).catch((err)=>{next(err);});}};
module.exports=asyncfunction({log,middlewareUtil,options,resources}){constMarkdownIt=require("markdown-it");constmd=newMarkdownIt();returnfunction(req,res,next){if(!req.path||!req.path.endsWith(".html")){// Do not handle non-HTML requestsnext();return;}// Try to read a corresponding markdown fileresources.rootProject.byPath(req.path.replace(".html",".md")).then(async(resource)=>{if(!resource){// No file found, hand over to next middlewarenext();return;}log.info(`Rendering markdown for ${resource.getPath()}`);constmarkdown=awaitresource.getBuffer();// Generate HTML from markdown stringconsthtml=md.render(markdown.toString());res.type('.html');res.end(html);}).catch((err)=>{next(err);});}};
In this case, a middlewareUtil object is provided as a part of the custom middleware's parameters. Depending on the specification version of the custom middleware, a set of helper functions is available to the implementation. The lowest required specification version for every function is listed in the MiddlewareUtil API reference.