As a LoopBack developer, I would like to have my RestServer provide static file hosting so that I can retrieve front-end content (HTML/CSS/JS).
(Additional note: This functionality would be required for an API Explorer Component)
RestServer and RestApplication to allow app developers to mount static middleware, for example app.static(path, options). Leverage Express middleware server-static to implement the actual file serving.Stretch goals:
Removed from scope by @bajtos on 2018-06-25:
/src/publicWe are targeting API server developers for MVP release. Serving static files (e.g. single-page applications) is out of scope of that. We should revisit this after MVP and decide what different kinds of servers we want to support in LoopBack 4+
Useful links to check out:
https://github.com/expressjs/serve-static
https://www.npmjs.com/package/mime
Might be able to resolve in https://github.com/strongloop/loopback-next/issues/1038.
cc @raymondfeng
I am taking this up. This will pave the way for the development of our middleware interface.
Don't we get this as a freebie when we switch to Express since it supports static file serving. We can just set it up for a default folder in basic app scaffolding (CLI) once the switch to Express has been made.
From my understanding, yes, we should get it for free after the switch to Express, or at least very minimal effort.
Since this is marked as non-DP3, we should evaluate what needs to be done (hopefully none). If there's work, we'll then defer it since it's not a DP3 item to begin with.
Yes, it comes baked in with Express. I was thinking more along the middleware interface we'll expose. With access to the Express instance and the app, users can enable this on their own. So, let's not touch this for now, we can create another story for the middleware interface.
Cross-posting https://github.com/strongloop/loopback-next/issues/559#issuecomment-399077339
I am proposing to enhance RestServer/RestApplication with an API allowing consumers to mount static files, for example
app.static(path, options). This API should leverage Express middleware server-static as an implementation detail.With this new API in place, we can either write an API Explorer component bundling swagger-ui and calling
app.static(pathToSwaggerUI), or preferably write a short guide explaining LB4 users how to add swagger-ui to their project themselves.
Let's re-estimate this story based on the fact that Express is already a part of RestServer implementation.
I am using angular as my front-end and I use the angular universal, that allows me to render my angular app on server side. With a few lines I can write a express server to render the angular app and send static files like assets and JavaScript files. Now I am looking for a back-end and I find out Loopback 4 is awesome.
I can easily have my express app doing what I am doing above and have the loopback api listening in a different port in a different app with a nginx server proxying the api/* calls to loopback and the other calls to the express app. But it would be great if I can have all that in a single app.
When I render the angular app on the server, most time I have to call the api doing http calls. With a single server app, I can use loopback repositories directly in the angular app instead making http calls.
Having saying that, what is the right way to delivery html from the loopback app? Beside that, how can I prefix all rest calls with /api/ and router all urls not starting with /api/ to the function that deliveries the html responses?
By saying "prefix all rest calls with /api/" I mean that if I use a decorator in a controller
@get('persons/{id}')
getPerson( ... ) {
...
}
then loopback routes /api/persons/{id} instead /persons/{id} to that method.
For now I am doing trying to do the following
async handle(context: RequestContext) {
try {
const {request, response} = context;
if (!request.path.startsWith('/api/')) {
response.contentType('text/html');
response.send('<h1>Hello world</h1>');
return;
}
// the line below doesn't work because request.url has only getter
// request.url = request.url.substr(4);
const args = await this.parseParams(request, route);
const result = await this.invoke(route, args);
this.send(response, result);
} catch (err) {
this.reject(context, err);
}
}
I solved the problem in this way

Having saying that, what is the right way to delivery html from the loopback app?
We don't have a proper solution for this yet, that's what this github issue is tracking. See https://github.com/strongloop/loopback-next/pull/1611 for the current work in progress.
Beside that, how can I prefix all rest calls with /api/ and router all urls not starting with /api/ to the function that deliveries the html responses?
In the future, we would like to introduce basePath option allowing developers to specify path prefix, see https://github.com/strongloop/loopback-next/issues/918 and https://github.com/strongloop/loopback-next/issues/914
A possible workaround solution addressing both problems you are facing: mount LB4 app as a middleware on top of your "main" express app.
const mainApp = express();
const apiApp = new MyLb4Application();
mainApp.use('/api', apiApp.requestHandler);
mainApp.use(express.static('./assets'));
mainApp.listen(3000);
const mainApp = express(); const apiApp = new MyLb4Application(); mainApp.use('/api', apiApp.requestHandler); mainApp.use(express.static('./assets')); mainApp.listen(3000);@bajtos Amazing. With that solution I can continue using my existing express app and start using loopback straight away without any refactoring. Thanks.
I suggest to put that use case in documentation. I see loopback as a api only. Using loopback like in your suggestion I can have my main app doing other things and loopback focusing in api only. As I didn't know that I was able to do that, I started using apollo server, that has a express middleware that allow me to do exactly what you suggested.
@csbenjamin I am glad my solution works for you 馃憤
I suggest to put that use case in documentation
That's a great idea. Could you please contribute that change yourself?
I am not sure what would be the best place where to add this content. To keep things easy for you, I think it will be best to add a new question & answer to our FAQ by editing the following file: docs/site/FAQ.md. We can move the content around later, if/when we find a better home of it.
It may be worth adding a cross-reference to Why express behind the scene too, what do you think?
See the following page for guides explaining how to contribute documentation: https://github.com/strongloop/loopback-next/blob/master/docs/CONTRIBUTING.md#documentation
We agreed with @dhmlau and @raymondfeng to create follow-up narrowly-focused stories for the features that are missing and close this story once they are created. I'll create the stories next week, I am thinking about:
/.Follow-up stories to address missing pieces:
Most helpful comment
We don't have a proper solution for this yet, that's what this github issue is tracking. See https://github.com/strongloop/loopback-next/pull/1611 for the current work in progress.
In the future, we would like to introduce
basePathoption allowing developers to specify path prefix, see https://github.com/strongloop/loopback-next/issues/918 and https://github.com/strongloop/loopback-next/issues/914A possible workaround solution addressing both problems you are facing: mount LB4 app as a middleware on top of your "main" express app.