Skip to content

Proper CLI with commander #603

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

Merged
merged 7 commits into from
Feb 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,28 @@ app.listen(1337, function() {

### Standalone Parse Server

Parse Server can also run as a standalone API server. The standalone Parse Server can be configured using [environment variables](#configuration). To start the server, just run `npm start`.
Parse Server can also run as a standalone API server.
You can configure Parse Server with a configuration file, arguments and environment variables.

To start the server:

`npm start -- --appId MYAPP --masterKey MASTER_KEY --serverURL http://localhost:1337/parse`.

To get more help for running the parse-server standalone, you can run:

`$ npm start -- --help`

The standalone API server supports loading a configuration file in JSON format:

`$ npm start -- path/to/your/config.json`

The default port is 1337, to use a different port set the PORT environment variable:
Copy link
Contributor

Choose a reason for hiding this comment

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

I see you updated the code for this setting but you forgot to update the docs :p

Copy link
Contributor Author

Choose a reason for hiding this comment

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

idiot me, actually that still works :)


`$ PORT=8080 npm start -- path/to/your/config.json`

The standalone Parse Server can be configured using [environment variables](#configuration).

Please refer to the [configuration section](#configuration) or help;

You can also install Parse Server globally:

Expand Down Expand Up @@ -92,6 +113,7 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
* `loggerAdapter` - The default behavior/transport (File) can be changed by creating an adapter class (see [`LoggerAdapter.js`](https://github.com/ParsePlatform/parse-server/blob/master/src/Adapters/Logger/LoggerAdapter.js))
* `enableAnonymousUsers` - Defaults to true. Set to false to disable anonymous users.
* `oauth` - Used to configure support for [3rd party authentication](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth).
* `maxUploadSize` - Defaults to 20mb. Max file size for uploads

#### Using environment variables

Expand All @@ -110,6 +132,7 @@ PARSE_SERVER_JAVASCRIPT_KEY
PARSE_SERVER_DOTNET_KEY
PARSE_SERVER_FILE_KEY
PARSE_SERVER_FACEBOOK_APP_IDS // string of comma separated list
PARSE_SERVER_MAX_UPLOAD_SIZE

```

Expand Down
47 changes: 1 addition & 46 deletions bin/parse-server
Original file line number Diff line number Diff line change
@@ -1,47 +1,2 @@
#!/usr/bin/env node
var express = require('express');
var ParseServer = require("../lib/index").ParseServer;

var app = express();

var options = {};
if (process.env.PARSE_SERVER_OPTIONS) {

options = JSON.parse(process.env.PARSE_SERVER_OPTIONS);

} else {

options.databaseURI = process.env.PARSE_SERVER_DATABASE_URI;
options.cloud = process.env.PARSE_SERVER_CLOUD_CODE_MAIN;
options.collectionPrefix = process.env.PARSE_SERVER_COLLECTION_PREFIX;

// Keys and App ID
options.appId = process.env.PARSE_SERVER_APPLICATION_ID;
options.clientKey = process.env.PARSE_SERVER_CLIENT_KEY;
options.restAPIKey = process.env.PARSE_SERVER_REST_API_KEY;
options.dotNetKey = process.env.PARSE_SERVER_DOTNET_KEY;
options.javascriptKey = process.env.PARSE_SERVER_JAVASCRIPT_KEY;
options.masterKey = process.env.PARSE_SERVER_MASTER_KEY;
options.fileKey = process.env.PARSE_SERVER_FILE_KEY;
// Comma separated list of facebook app ids
var facebookAppIds = process.env.PARSE_SERVER_FACEBOOK_APP_IDS;

if (facebookAppIds) {
facebookAppIds = facebookAppIds.split(",");
options.facebookAppIds = facebookAppIds;
}

var oauth = process.env.PARSE_SERVER_OAUTH_PROVIDERS;
if (oauth) {
options.oauth = JSON.parse(oauth);
};
}

var mountPath = process.env.PARSE_SERVER_MOUNT_PATH || "/";
var api = new ParseServer(options);
app.use(mountPath, api);

var port = process.env.PORT || 1337;
app.listen(port, function() {
console.log('parse-server-example running on http://localhost:'+ port + mountPath);
});
require("../lib/cli/parse-server");
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"babel-runtime": "^6.5.0",
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.14.2",
"colors": "^1.1.2",
"commander": "^2.9.0",
"deepcopy": "^0.6.1",
"express": "^4.13.4",
"mime": "^1.3.4",
Expand Down
87 changes: 87 additions & 0 deletions spec/CLI.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
var commander = require("../src/cli/utils/commander").default;

var definitions = {
"arg0": "PROGRAM_ARG_0",
"arg1": {
env: "PROGRAM_ARG_1",
required: true
},
"arg2": {
env: "PROGRAM_ARG_2",
action: function(value) {
var value = parseInt(value);
if (!Number.isInteger(value)) {
throw "port is invalid";
}
return value;
}
},
"arg3": {},
"arg4": {
default: "arg4Value"
}
}

describe("commander additions", () => {

afterEach((done) => {
commander.options = [];
delete commander.arg0;
delete commander.arg1;
delete commander.arg2;
delete commander.arg3;
delete commander.arg4;
done();
})

it("should load properly definitions from args", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg1", "arg1Value", "--arg2", "2", "--arg3", "some"]);
expect(commander.arg0).toEqual("arg0Value");
expect(commander.arg1).toEqual("arg1Value");
expect(commander.arg2).toEqual(2);
expect(commander.arg3).toEqual("some");
expect(commander.arg4).toEqual("arg4Value");
done();
});

it("should load properly definitions from env", (done) => {
commander.loadDefinitions(definitions);
commander.parse([], {
"PROGRAM_ARG_0": "arg0ENVValue",
"PROGRAM_ARG_1": "arg1ENVValue",
"PROGRAM_ARG_2": "3",
});
expect(commander.arg0).toEqual("arg0ENVValue");
expect(commander.arg1).toEqual("arg1ENVValue");
expect(commander.arg2).toEqual(3);
expect(commander.arg4).toEqual("arg4Value");
done();
});

it("should load properly use args over env", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg4", "anotherArg4"], {
"PROGRAM_ARG_0": "arg0ENVValue",
"PROGRAM_ARG_1": "arg1ENVValue",
"PROGRAM_ARG_2": "4",
});
expect(commander.arg0).toEqual("arg0Value");
expect(commander.arg1).toEqual("arg1ENVValue");
expect(commander.arg2).toEqual(4);
expect(commander.arg4).toEqual("anotherArg4");
done();
});

it("should fail in action as port is invalid", (done) => {
commander.loadDefinitions(definitions);
expect(()=> {
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value"], {
"PROGRAM_ARG_0": "arg0ENVValue",
"PROGRAM_ARG_1": "arg1ENVValue",
"PROGRAM_ARG_2": "hello",
});
}).toThrow("port is invalid");
done();
});
});
110 changes: 110 additions & 0 deletions src/cli/cli-definitions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
export default {
"appId": {
env: "PARSE_SERVER_APPLICATION_ID",
help: "Your Parse Application ID",
required: true
},
"masterKey": {
env: "PARSE_SERVER_MASTER_KEY",
help: "Your Parse Master Key",
required: true
},
"port": {
port: "PORT",
help: "The port to run the ParseServer. defaults to 1337.",
default: 1337,
action: function(opt) {
opt = parseInt(opt);
if (!Number.isInteger(opt)) {
throw new Error("The port is invalid");
}
return opt;
}
},
"databaseURI": {
env: "PARSE_SERVER_DATABASE_URI",
help: "The full URI to your mongodb database"
},
"serverURL": {
env: "PARSE_SERVER_URL",
help: "URL to your parse server with http:// or https://.",
},
"clientKey": {
env: "PARSE_SERVER_CLIENT_KEY",
help: "Key for iOS, MacOS, tvOS clients"
},
"javascriptKey": {
env: "PARSE_SERVER_JAVASCRIPT_KEY",
help: "Key for the Javascript SDK"
},
"restAPIKey": {
env: "PARSE_SERVER_REST_API_KEY",
help: "Key for REST calls"
},
"dotNetKey": {
env: "PARSE_SERVER_DOT_NET_KEY",
help: "Key for Unity and .Net SDK"
},
"cloud": {
env: "PARSE_SERVER_CLOUD_CODE_MAIN",
help: "Full path to your cloud code main.js"
},
"push": {
env: "PARSE_SERVER_PUSH",
help: "Configuration for push, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Push",
action: function(opt) {
return JSON.parse(opt)
}
},
"oauth": {
env: "PARSE_SERVER_OAUTH_PROVIDERS",
help: "Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
action: function(opt) {
return JSON.parse(opt)
}
},
"fileKey": {
env: "PARSE_SERVER_FILE_KEY",
help: "Key for your files",
},
"facebookAppIds": {
env: "PARSE_SERVER_FACEBOOK_APP_IDS",
help: "Comma separated list for your facebook app Ids",
type: "list",
action: function(opt) {
return opt.split(",")
}
},
"enableAnonymousUsers": {
env: "PARSE_SERVER_ENABLE_ANON_USERS",
help: "Enable (or disable) anon users, defaults to true",
action: function(opt) {
if (opt == "true" || opt == "1") {
return true;
}
return false;
}
},
"mountPath": {
env: "PARSE_SERVER_MOUNT_PATH",
help: "Mount path for the server, defaults to /parse",
default: "/parse"
},
"databaseAdapter": {
env: "PARSE_SERVER_DATABASE_ADAPTER",
help: "Adapter module for the database sub-system"
},
"filesAdapter": {
env: "PARSE_SERVER_FILES_ADAPTER",
help: "Adapter module for the files sub-system"
},
"loggerAdapter": {
env: "PARSE_SERVER_LOGGER_ADAPTER",
help: "Adapter module for the logging sub-system"
},
"maxUploadSize": {
env: "PARSE_SERVER_MAX_UPLOAD_SIZE",
help: "Max file size for uploads.",
default: "20mb"
}
};
79 changes: 79 additions & 0 deletions src/cli/parse-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import path from 'path';
import express from 'express';
import { ParseServer } from '../index';
import definitions from './cli-definitions';
import program from './utils/commander';
import colors from 'colors';

program.loadDefinitions(definitions);

program
.usage('[options] <path/to/configuration.json>');

program.on('--help', function(){
console.log(' Get Started guide:');
console.log('');
console.log(' Please have a look at the get started guide!')
console.log(' https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide');
console.log('');
console.log('');
console.log(' Usage with npm start');
console.log('');
console.log(' $ npm start -- path/to/config.json');
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log('');
console.log('');
console.log(' Usage:');
console.log('');
console.log(' $ parse-server path/to/config.json');
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
console.log('');
});

program.parse(process.argv, process.env);

let options;
if (program.args.length > 0 ) {
let jsonPath = program.args[0];
jsonPath = path.resolve(jsonPath);
options = require(jsonPath);
console.log(`Configuation loaded from ${jsonPath}`)
}

if (!program.appId || !program.masterKey || !program.serverURL) {
program.outputHelp();
console.error("");
console.error(colors.red("ERROR: appId, masterKey and serverURL are required"));
console.error("");
process.exit(1);
}

options = Object.keys(definitions).reduce(function (options, key) {
if (program[key]) {
options[key] = program[key];
}
return options;
}, options);

if (!options.serverURL) {
options.serverURL = `http://localhost:${options.port}${options.mountPath}`;
}

const app = express();
const api = new ParseServer(options);
app.use(options.mountPath, api);

app.listen(options.port, function() {

for (let key in options) {
let value = options[key];
if (key == "masterKey") {
value = "***REDACTED***";
}
console.log(`${key}: ${value}`);
}
console.log('');
console.log('parse-server running on '+options.serverURL);
});
Loading