Skip to content

Commit a7262da

Browse files
committed
Merge pull request #603 from flovilmart/proper-cli
Proper CLI with commander
2 parents e58aa54 + db5338a commit a7262da

File tree

7 files changed

+388
-47
lines changed

7 files changed

+388
-47
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,28 @@ app.listen(1337, function() {
4444

4545
### Standalone Parse Server
4646

47-
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`.
47+
Parse Server can also run as a standalone API server.
48+
You can configure Parse Server with a configuration file, arguments and environment variables.
49+
50+
To start the server:
51+
52+
`npm start -- --appId MYAPP --masterKey MASTER_KEY --serverURL http://localhost:1337/parse`.
53+
54+
To get more help for running the parse-server standalone, you can run:
55+
56+
`$ npm start -- --help`
57+
58+
The standalone API server supports loading a configuration file in JSON format:
59+
60+
`$ npm start -- path/to/your/config.json`
61+
62+
The default port is 1337, to use a different port set the PORT environment variable:
63+
64+
`$ PORT=8080 npm start -- path/to/your/config.json`
65+
66+
The standalone Parse Server can be configured using [environment variables](#configuration).
67+
68+
Please refer to the [configuration section](#configuration) or help;
4869

4970
You can also install Parse Server globally:
5071

@@ -92,6 +113,7 @@ The client keys used with Parse are no longer necessary with Parse Server. If yo
92113
* `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))
93114
* `enableAnonymousUsers` - Defaults to true. Set to false to disable anonymous users.
94115
* `oauth` - Used to configure support for [3rd party authentication](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth).
116+
* `maxUploadSize` - Defaults to 20mb. Max file size for uploads
95117

96118
#### Using environment variables
97119

@@ -110,6 +132,7 @@ PARSE_SERVER_JAVASCRIPT_KEY
110132
PARSE_SERVER_DOTNET_KEY
111133
PARSE_SERVER_FILE_KEY
112134
PARSE_SERVER_FACEBOOK_APP_IDS // string of comma separated list
135+
PARSE_SERVER_MAX_UPLOAD_SIZE
113136

114137
```
115138

bin/parse-server

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,2 @@
11
#!/usr/bin/env node
2-
var express = require('express');
3-
var ParseServer = require("../lib/index").ParseServer;
4-
5-
var app = express();
6-
7-
var options = {};
8-
if (process.env.PARSE_SERVER_OPTIONS) {
9-
10-
options = JSON.parse(process.env.PARSE_SERVER_OPTIONS);
11-
12-
} else {
13-
14-
options.databaseURI = process.env.PARSE_SERVER_DATABASE_URI;
15-
options.cloud = process.env.PARSE_SERVER_CLOUD_CODE_MAIN;
16-
options.collectionPrefix = process.env.PARSE_SERVER_COLLECTION_PREFIX;
17-
18-
// Keys and App ID
19-
options.appId = process.env.PARSE_SERVER_APPLICATION_ID;
20-
options.clientKey = process.env.PARSE_SERVER_CLIENT_KEY;
21-
options.restAPIKey = process.env.PARSE_SERVER_REST_API_KEY;
22-
options.dotNetKey = process.env.PARSE_SERVER_DOTNET_KEY;
23-
options.javascriptKey = process.env.PARSE_SERVER_JAVASCRIPT_KEY;
24-
options.masterKey = process.env.PARSE_SERVER_MASTER_KEY;
25-
options.fileKey = process.env.PARSE_SERVER_FILE_KEY;
26-
// Comma separated list of facebook app ids
27-
var facebookAppIds = process.env.PARSE_SERVER_FACEBOOK_APP_IDS;
28-
29-
if (facebookAppIds) {
30-
facebookAppIds = facebookAppIds.split(",");
31-
options.facebookAppIds = facebookAppIds;
32-
}
33-
34-
var oauth = process.env.PARSE_SERVER_OAUTH_PROVIDERS;
35-
if (oauth) {
36-
options.oauth = JSON.parse(oauth);
37-
};
38-
}
39-
40-
var mountPath = process.env.PARSE_SERVER_MOUNT_PATH || "/";
41-
var api = new ParseServer(options);
42-
app.use(mountPath, api);
43-
44-
var port = process.env.PORT || 1337;
45-
app.listen(port, function() {
46-
console.log('parse-server-example running on http://localhost:'+ port + mountPath);
47-
});
2+
require("../lib/cli/parse-server");

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"babel-runtime": "^6.5.0",
2323
"bcrypt-nodejs": "0.0.3",
2424
"body-parser": "^1.14.2",
25+
"colors": "^1.1.2",
26+
"commander": "^2.9.0",
2527
"deepcopy": "^0.6.1",
2628
"express": "^4.13.4",
2729
"mime": "^1.3.4",

spec/CLI.spec.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
var commander = require("../src/cli/utils/commander").default;
2+
3+
var definitions = {
4+
"arg0": "PROGRAM_ARG_0",
5+
"arg1": {
6+
env: "PROGRAM_ARG_1",
7+
required: true
8+
},
9+
"arg2": {
10+
env: "PROGRAM_ARG_2",
11+
action: function(value) {
12+
var value = parseInt(value);
13+
if (!Number.isInteger(value)) {
14+
throw "port is invalid";
15+
}
16+
return value;
17+
}
18+
},
19+
"arg3": {},
20+
"arg4": {
21+
default: "arg4Value"
22+
}
23+
}
24+
25+
describe("commander additions", () => {
26+
27+
afterEach((done) => {
28+
commander.options = [];
29+
delete commander.arg0;
30+
delete commander.arg1;
31+
delete commander.arg2;
32+
delete commander.arg3;
33+
delete commander.arg4;
34+
done();
35+
})
36+
37+
it("should load properly definitions from args", (done) => {
38+
commander.loadDefinitions(definitions);
39+
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg1", "arg1Value", "--arg2", "2", "--arg3", "some"]);
40+
expect(commander.arg0).toEqual("arg0Value");
41+
expect(commander.arg1).toEqual("arg1Value");
42+
expect(commander.arg2).toEqual(2);
43+
expect(commander.arg3).toEqual("some");
44+
expect(commander.arg4).toEqual("arg4Value");
45+
done();
46+
});
47+
48+
it("should load properly definitions from env", (done) => {
49+
commander.loadDefinitions(definitions);
50+
commander.parse([], {
51+
"PROGRAM_ARG_0": "arg0ENVValue",
52+
"PROGRAM_ARG_1": "arg1ENVValue",
53+
"PROGRAM_ARG_2": "3",
54+
});
55+
expect(commander.arg0).toEqual("arg0ENVValue");
56+
expect(commander.arg1).toEqual("arg1ENVValue");
57+
expect(commander.arg2).toEqual(3);
58+
expect(commander.arg4).toEqual("arg4Value");
59+
done();
60+
});
61+
62+
it("should load properly use args over env", (done) => {
63+
commander.loadDefinitions(definitions);
64+
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg4", "anotherArg4"], {
65+
"PROGRAM_ARG_0": "arg0ENVValue",
66+
"PROGRAM_ARG_1": "arg1ENVValue",
67+
"PROGRAM_ARG_2": "4",
68+
});
69+
expect(commander.arg0).toEqual("arg0Value");
70+
expect(commander.arg1).toEqual("arg1ENVValue");
71+
expect(commander.arg2).toEqual(4);
72+
expect(commander.arg4).toEqual("anotherArg4");
73+
done();
74+
});
75+
76+
it("should fail in action as port is invalid", (done) => {
77+
commander.loadDefinitions(definitions);
78+
expect(()=> {
79+
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value"], {
80+
"PROGRAM_ARG_0": "arg0ENVValue",
81+
"PROGRAM_ARG_1": "arg1ENVValue",
82+
"PROGRAM_ARG_2": "hello",
83+
});
84+
}).toThrow("port is invalid");
85+
done();
86+
});
87+
});

src/cli/cli-definitions.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
export default {
2+
"appId": {
3+
env: "PARSE_SERVER_APPLICATION_ID",
4+
help: "Your Parse Application ID",
5+
required: true
6+
},
7+
"masterKey": {
8+
env: "PARSE_SERVER_MASTER_KEY",
9+
help: "Your Parse Master Key",
10+
required: true
11+
},
12+
"port": {
13+
port: "PORT",
14+
help: "The port to run the ParseServer. defaults to 1337.",
15+
default: 1337,
16+
action: function(opt) {
17+
opt = parseInt(opt);
18+
if (!Number.isInteger(opt)) {
19+
throw new Error("The port is invalid");
20+
}
21+
return opt;
22+
}
23+
},
24+
"databaseURI": {
25+
env: "PARSE_SERVER_DATABASE_URI",
26+
help: "The full URI to your mongodb database"
27+
},
28+
"serverURL": {
29+
env: "PARSE_SERVER_URL",
30+
help: "URL to your parse server with http:// or https://.",
31+
},
32+
"clientKey": {
33+
env: "PARSE_SERVER_CLIENT_KEY",
34+
help: "Key for iOS, MacOS, tvOS clients"
35+
},
36+
"javascriptKey": {
37+
env: "PARSE_SERVER_JAVASCRIPT_KEY",
38+
help: "Key for the Javascript SDK"
39+
},
40+
"restAPIKey": {
41+
env: "PARSE_SERVER_REST_API_KEY",
42+
help: "Key for REST calls"
43+
},
44+
"dotNetKey": {
45+
env: "PARSE_SERVER_DOT_NET_KEY",
46+
help: "Key for Unity and .Net SDK"
47+
},
48+
"cloud": {
49+
env: "PARSE_SERVER_CLOUD_CODE_MAIN",
50+
help: "Full path to your cloud code main.js"
51+
},
52+
"push": {
53+
env: "PARSE_SERVER_PUSH",
54+
help: "Configuration for push, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Push",
55+
action: function(opt) {
56+
return JSON.parse(opt)
57+
}
58+
},
59+
"oauth": {
60+
env: "PARSE_SERVER_OAUTH_PROVIDERS",
61+
help: "Configuration for your oAuth providers, as stringified JSON. See https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#oauth",
62+
action: function(opt) {
63+
return JSON.parse(opt)
64+
}
65+
},
66+
"fileKey": {
67+
env: "PARSE_SERVER_FILE_KEY",
68+
help: "Key for your files",
69+
},
70+
"facebookAppIds": {
71+
env: "PARSE_SERVER_FACEBOOK_APP_IDS",
72+
help: "Comma separated list for your facebook app Ids",
73+
type: "list",
74+
action: function(opt) {
75+
return opt.split(",")
76+
}
77+
},
78+
"enableAnonymousUsers": {
79+
env: "PARSE_SERVER_ENABLE_ANON_USERS",
80+
help: "Enable (or disable) anon users, defaults to true",
81+
action: function(opt) {
82+
if (opt == "true" || opt == "1") {
83+
return true;
84+
}
85+
return false;
86+
}
87+
},
88+
"mountPath": {
89+
env: "PARSE_SERVER_MOUNT_PATH",
90+
help: "Mount path for the server, defaults to /parse",
91+
default: "/parse"
92+
},
93+
"databaseAdapter": {
94+
env: "PARSE_SERVER_DATABASE_ADAPTER",
95+
help: "Adapter module for the database sub-system"
96+
},
97+
"filesAdapter": {
98+
env: "PARSE_SERVER_FILES_ADAPTER",
99+
help: "Adapter module for the files sub-system"
100+
},
101+
"loggerAdapter": {
102+
env: "PARSE_SERVER_LOGGER_ADAPTER",
103+
help: "Adapter module for the logging sub-system"
104+
},
105+
"maxUploadSize": {
106+
env: "PARSE_SERVER_MAX_UPLOAD_SIZE",
107+
help: "Max file size for uploads.",
108+
default: "20mb"
109+
}
110+
};

src/cli/parse-server.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import path from 'path';
2+
import express from 'express';
3+
import { ParseServer } from '../index';
4+
import definitions from './cli-definitions';
5+
import program from './utils/commander';
6+
import colors from 'colors';
7+
8+
program.loadDefinitions(definitions);
9+
10+
program
11+
.usage('[options] <path/to/configuration.json>');
12+
13+
program.on('--help', function(){
14+
console.log(' Get Started guide:');
15+
console.log('');
16+
console.log(' Please have a look at the get started guide!')
17+
console.log(' https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide');
18+
console.log('');
19+
console.log('');
20+
console.log(' Usage with npm start');
21+
console.log('');
22+
console.log(' $ npm start -- path/to/config.json');
23+
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
24+
console.log(' $ npm start -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
25+
console.log('');
26+
console.log('');
27+
console.log(' Usage:');
28+
console.log('');
29+
console.log(' $ parse-server path/to/config.json');
30+
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
31+
console.log(' $ parse-server -- --appId APP_ID --masterKey MASTER_KEY --serverURL serverURL');
32+
console.log('');
33+
});
34+
35+
program.parse(process.argv, process.env);
36+
37+
let options;
38+
if (program.args.length > 0 ) {
39+
let jsonPath = program.args[0];
40+
jsonPath = path.resolve(jsonPath);
41+
options = require(jsonPath);
42+
console.log(`Configuation loaded from ${jsonPath}`)
43+
}
44+
45+
if (!program.appId || !program.masterKey || !program.serverURL) {
46+
program.outputHelp();
47+
console.error("");
48+
console.error(colors.red("ERROR: appId, masterKey and serverURL are required"));
49+
console.error("");
50+
process.exit(1);
51+
}
52+
53+
options = Object.keys(definitions).reduce(function (options, key) {
54+
if (program[key]) {
55+
options[key] = program[key];
56+
}
57+
return options;
58+
}, options);
59+
60+
if (!options.serverURL) {
61+
options.serverURL = `http://localhost:${options.port}${options.mountPath}`;
62+
}
63+
64+
const app = express();
65+
const api = new ParseServer(options);
66+
app.use(options.mountPath, api);
67+
68+
app.listen(options.port, function() {
69+
70+
for (let key in options) {
71+
let value = options[key];
72+
if (key == "masterKey") {
73+
value = "***REDACTED***";
74+
}
75+
console.log(`${key}: ${value}`);
76+
}
77+
console.log('');
78+
console.log('parse-server running on '+options.serverURL);
79+
});

0 commit comments

Comments
 (0)