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

Add support for "booting" an application from a set of Model / DataSource / app meta-data. #57

Closed
wants to merge 3 commits into from

Conversation

ritch
Copy link
Member

@ritch ritch commented Oct 29, 2013

/to @raymondfeng
/cc @bajtos @piscisaureus @sam-github @themitchy @Schoonology

Background

Here is a detailed example application using the new app.boot() api. The sample app shows how using app.boot() can simplify our project structure.

Current Project Structure

Currently slc lb generates a set of modules and an entry file (app.js). app.js is a module loader that is baked in as part of the generated code. It require()s each module in the modules directory and starts the app. Each module is made up of generated code (index.js) a module description (module.json) that defines meta-data about the module and one or more config files (config.json, properties.json).

Issues with the Current Structure

"There are too many files named index.js"

"data sources, apps, models, are all top-level structures without explicit type in the folder hierarchy"

Since each "module" contains an index.js file, working on a loopback project usually means having several index.js files open. The example project linked above has clearly named files and directories (eg. models.json, ./models).

"A bare scaffolded model consists of 3 files and many lines, none of which I know what they are for."

The proposed structure wouldn't include any extra generated files. Instead slc lb would just update the models.json file when scaffolding a model or datasources.json when defining a datasource.

Propsoed Project Structure

The structure proposed in the example linked above is a bit simpler. There are three config files:

  • app.json
  • models.json
  • datasources.json

Plus a single entry file:

  • app.js

app.js is the only file with generated code. It includes the following:

var loopback = require('loopback');
var app = module.exports = loopback();

// express compatible middleware
app.use(loopback.favicon());
app.use(loopback.logger('dev'));
app.use(loopback.bodyParser());
app.use(loopback.methodOverride());
app.use(app.router);
app.use(loopback.static(path.join(__dirname, 'public')));

// configure the app
// read more: <link to docs>
app.boot();

// development only
if ('development' == app.get('env')) {
  app.use(loopback.errorHandler());
}

// only start the server if this module
// is the main module...
if(require.main === module) {
  app.listen();
}

When app.boot() is called without any arguments, the following is kicked off:

  1. DataSources are created from datasources.json in the current directory
  2. Models are created from models.json in the current directory
  3. Any JavaScript files in the ./models dir are required.

New Simpler APIs

This PR also introduces a simpler way of defining and interacting with models:

First you define the data sources your app requires using app.boot().

app.boot({
  dataSources: {
    mongo: {connector: "mongodb", url: "mongodb://localhost:27015/my-db"}
  }
});

Then you can define a model in a single line:

var Product = app.model('product', {dataSource: 'mongo'});

Furthermore, your models are available from your app.

Product = require('../app').models.Product;

Read the updated documentation for more info.

@slnode
Copy link

slnode commented Oct 29, 2013

Test PASSed.
Refer to this link for build results: http://ci.strongloop.com/job/loopback/322/

@slnode
Copy link

slnode commented Oct 31, 2013

Test PASSed.
Refer to this link for build results: http://ci.strongloop.com/job/loopback/323/

app.model = function (Model, config) {
if(arguments.length === 1) {
assert(typeof Model === 'function', 'app.model(Model) => Model must be a function / constructor');
this.remotes().exports[Model.pluralModelName] = Model;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert that Model.pluralModelName is defined?

@bajtos
Copy link
Member

bajtos commented Nov 1, 2013

The new API and design are great, it looks it will be easy to work with it both manually (as a developer/user) and from an IDE/CLI tools.

See few comments above, my main concern is about using cwd.

@slnode
Copy link

slnode commented Nov 1, 2013

Test PASSed.
Refer to this link for build results: http://ci.strongloop.com/job/loopback/324/

@ritch ritch mentioned this pull request Nov 1, 2013
@ritch
Copy link
Member Author

ritch commented Nov 1, 2013

Closing this PR and opening a PR against the named branch that spans multiple repos.

@ritch ritch closed this Nov 1, 2013
ritch added a commit that referenced this pull request Nov 4, 2013
@sam-github
Copy link
Contributor

@ritch I apologize for the lateness of this, I've been excessively bogged down last week.

I like it, but have a few comments:

  • I liked the one-file per model better. I think the example here is already excessively hard to read, and will only get worse as the number of models increases. I'd prefer these to be broken up into file-per-model, and put into models/.
  • I don't understand the existence of app.json. Why is this not in app.js, or in app.boot()? Particularly when it has embedded javascript in the string?
  • It looks like this logger param should not be hard-coded to dev, maybe it should be app.get('env')?
  • Why are all the .use(...loopback...) lines not in app.boot(), or similarly factored out? Will loopback work if they are deleted? I'd guess not.
  • It looks to me like the model.json should be javascript, too. It uses js in it already. embedded into string comments, why not rename the extension and require it instead of JSON.parsing it?

Other than that, looks good.

@ritch
Copy link
Member Author

ritch commented Nov 5, 2013

I liked the one-file per model better. I think the example here is already excessively hard to read, and will only get worse as the number of models increases. I'd prefer these to be broken up into file-per-model, and put into models/.

You might have to be a bit more specific. If I understand correctly, I agree that having a single file for describing a model is much clearer and more comprehensible than a giagantic JSON file. We have to have JSON that describes the model so that we can generate the LDL / meta data from the editor. I'm not against supporting building models.json from multiple files. Its something that I think we can implement in a future version though.

I don't understand the existence of app.json. Why is this not in app.js, or in app.boot()? Particularly when it has embedded javascript in the string?

The embedded JS was an interesting idea to allow config to be paramaterized. We are going to solve this with a different approach. Like above, we need to be able to specify settings from the editor or other tools. That is why there is as little config / meta-data in the actual generated code as possible.

It looks like this logger param should not be hard-coded to dev, maybe it should be app.get('env')

Take a look at this PR it has the actual app.js code in it. strongloop/loopback-workspace#14

Why are all the .use(...loopback...) lines not in app.boot(), or similarly factored out? Will loopback work if they are deleted? I'd guess not.

Can we address this in the workspace PR mentioned above?

It looks to me like the model.json should be javascript, too. It uses js in it already. embedded into string comments, why not rename the extension and require it instead of JSON.parsing it?

Thought we already talked about this at some point. The config needs to be readable and writable. This means JS is not really a realistic option. I won't say anything is impossible, but AST parsing and rebuilding would be incredibly hard compared to JSON.stringify / JSON.parse.

@sam-github
Copy link
Contributor

http://esprima.org/, shouldn't be excessively hard to read/write js, and the inline js is basically writing out own templating engine, which isn't to be taken lightly. Just an idea. I'll comment on the other thread...

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

Successfully merging this pull request may close these issues.

5 participants