Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Explorer] - Add static file serving capabilities to RestServer #691

Closed
2 of 3 tasks
jannyHou opened this issue Oct 31, 2017 · 16 comments
Closed
2 of 3 tasks

[API Explorer] - Add static file serving capabilities to RestServer #691

jannyHou opened this issue Oct 31, 2017 · 16 comments
Assignees

Comments

@jannyHou
Copy link
Contributor

jannyHou commented Oct 31, 2017

Story

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)

Acceptance Criteria

  • Add a new API to both 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.
    • Should allow a user to specify a directory and tweak serve-static options
    • Should set the Content-Type header of the response based on the file's MIME type.
  • Add a short section/guide to our documentation explaining users how to use this new API.

Stretch goals:

Removed from scope by @bajtos on 2018-06-25:

  • Should default to /src/public
  • Should recursively map target directory's file and folder paths in memory (NOT THE CONTENT)
@jannyHou jannyHou self-assigned this Oct 31, 2017
@bajtos bajtos added the non-MVP label Nov 2, 2017
@bajtos
Copy link
Member

bajtos commented Nov 2, 2017

We 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+

@kjdelisle kjdelisle changed the title Serving static files Add static file serving capabilities to RestServer Nov 23, 2017
@kjdelisle kjdelisle changed the title Add static file serving capabilities to RestServer [API Explorer] - Add static file serving capabilities to RestServer Nov 23, 2017
@virkt25
Copy link
Contributor

virkt25 commented Nov 23, 2017

@dhmlau
Copy link
Member

dhmlau commented Mar 2, 2018

Might be able to resolve in #1038.
cc @raymondfeng

@hacksparrow hacksparrow self-assigned this Apr 26, 2018
@hacksparrow
Copy link
Contributor

hacksparrow commented Apr 26, 2018

I am taking this up. This will pave the way for the development of our middleware interface.

@virkt25
Copy link
Contributor

virkt25 commented Apr 26, 2018

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.

@dhmlau
Copy link
Member

dhmlau commented Apr 26, 2018

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.

@hacksparrow
Copy link
Contributor

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.

@bajtos bajtos added the p2 label Jun 25, 2018
@bajtos
Copy link
Member

bajtos commented Jun 25, 2018

Cross-posting #559 (comment)

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.

@csbenjamin
Copy link

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.

@csbenjamin
Copy link

csbenjamin commented Jul 31, 2018

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);
    }
  }

@ServisionFrontend
Copy link

I solved the problem in this way
image

@dhmlau dhmlau removed the non-DP3 label Aug 23, 2018
@bajtos
Copy link
Member

bajtos commented Aug 24, 2018

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 #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 #918 and #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);

@csbenjamin
Copy link

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.

@bajtos
Copy link
Member

bajtos commented Sep 3, 2018

@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

@dhmlau dhmlau removed the team-apex label Sep 25, 2018
@bajtos
Copy link
Member

bajtos commented Sep 25, 2018

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:

  • Unified error handler for both REST APIs and static content.
  • Performance - REST router must be invoked before static content handler(s). This will allow - static content to be mounted on /.

@bajtos
Copy link
Member

bajtos commented Oct 1, 2018

Follow-up stories to address missing pieces:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants