-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Adapters architecture #290
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
Comments
+1 |
The way I had implemented it was like this, although it doesn't support the service registry approach you're going for: See: https://gist.github.com/maysale01/5390485e676ee3745960 and https://github.com/ParsePlatform/parse-server/pull/291/files That pull request has a method function resolveAdapter(adapter, options) {
// Support passing in adapter paths
if (typeof adapter === 'string') {
adapter = require(adapter);
}
// Instantiate the adapter if the class got passed instead of an instance
if (typeof adapter === 'function') {
adapter = new adapter(options);
}
return adapter;
} resolveAdapter is used in the ParseServer constructor, but can also be used afterwards: let SendGridAdapter = require("parse-server-mailgun-adapter");
let server = new ParseServer({
applicationId: 12345,
mail: {
/* adapter can be a module name, class or object/instance */
/* if its a module name, it can resolve to either a class or object/instance */
adapter: "parse-server-mailgun-adapter",
options: {
apiKey: "12345"
}
},
cache: {
options: {
/* no adapter specified, using default */
defaultTtl: 20 * 60 * 1000
}
}
});
// All of the following are equivalent
let adapter = server.resolveAdapter("parse-server-mailgun-adapter", { apiKey: "12345" });
server.mailProvider.setAdapter(adapter);
adapter = server.resolveAdapter(SendGridAdapter, { apiKey: "12345" });
server.mailProvider.setAdapter(adapter);
adapter = new SendGridAdapter({ apiKey: "12345" });
server.mailProvider.setAdapter(adapter);
// If passed an object it just returns the object (options do nothing);
adapter = server.resolveAdapter(adapter);
server.mailProvider.setAdapter(adapter); |
@mysale01 that's real nice. We should leverage as much as we can npm to inject and configure adapters. That would also reduce the size of the code base and make it more maintainable. In that sense, I would even go as far as putting the base email adapter in an external repo and as a dependency. |
Indeed. I think it all centers around whether or not "Parse Server" is a On Sunday, February 7, 2016, Florent Vilmart [email protected]
|
So moving towards that direction we need a refactor of the Adapter architecture, then we can modularize pretty much everything. If the maintainers decide to move a module externally, that won't change anything, but the default string in the require call. Goes hands in hands with #275, #282, #151, maybe #186 and possibly more. |
Thanks for starting this discussion. One thing that really excites me about having an open source version of Parse is the ability to have much more powerful configuration options. It wasn't possible on Parse.com to use JS functions in configuration due to security issues, process isolation issues, and other multi-tenant issues. But having a single tenant parse-server opens the door door to things like what I mentioned in #275 about having a mailer that generates mail based on fields on the current Having the configuration be in a separate place from the actual server app could also be useful in helping guys like Heroku provide a web based configuration and easy "getting started" flow, which I think could be awesome for beginner developers who are maybe making their first app that has a web component (or maybe even their first time programming at all) I really like where this discussion is going :) here is my suggestion for an interface: Config method 1: Pass an object that conforms to an interface in the configuration object. This will satisfy the power users who want full control over everything that goes on in their application, and enables some fancy features.
The REALLY advanced users can even implement the adapter directly, which probably doesn't make much sense for the big things like email or database adapters, but could make sense for smaller things, like choosing where Cloud Code is loaded from (if we expose that as an extensibility point):
Config option 2: Have the server also accept the npm-module-name approach. This allows simple configurations to be pure JSON, which will make life easier for the people building parse hosting services. @maysale01 I think this also covers the use cases for having the config be a class, but if not please let me know, I'm sure we could have that as option as well if you had some use cases in mind.
I personally dislike having a lot of places where you check the Having the parse-server generally be designed to be used standalone I think is a good idea. If thats the case, that would mean things like changing an adapter or it's options while the server is running would be a little weird and maybe that isn't something we should spend a lot of effort supporting. Happy to hear other opinions though. @maysale01 if we moved the core logic to |
Re: parse-express Re: Adapter submodules Re: Adapter configuration // Instance.
import { default as MemoryCache } from 'parse-server-memory-cache';
new ParseServer({
cache: {
adapter: new MemoryCache({ defaultTtl: 10 * 60 * 1000 })
}
});
// Override methods
MemoryCache.prototype.filter = myFilterFn;
new ParseServer({
cache: {
adapter: new MemoryCache({ defaultTtl: 10 * 60 * 1000 })
}
}); // Class/Function.
// Useful if the provider needs to create future instances, e.g. multiple apps with distinct caches
import { default as MemoryCache } from 'parse-server-memory-cache';
new ParseServer({
cache: {
adapter: MemoryCache,
options: {
defaultTtl: Infinity
}
}
}); // String. Allows the config to be dynamic, e.g. JSON payload
// The module could return an object, instance, or class (constructor function) .
new ParseServer({
cache: {
adapter: "parse-server-memory-cache",
options: {
defaultTtl: Infinity
}
}
}); // Object.
new ParseServer({
cache: {
adapter: {
put: (key, value) => { ... },
del: (key) => { ... },
get: (key) => { ... },
clear: () => { ... }
}
}
}); |
I don't know what you guys are talking about but it sounds Smart and I like that! Keep it up! :) |
@maysale01 this looks like a good interface for adapters. You have a very good point about NPM versioning and having a default adapter class for multiple apps. I'm still not sure about moving the core logic to |
@drew-gross I'm reimplementing the whole cloud code stack now, in sub processes, and also to allow external servers to run cloud code for the multiple apps implementation. I just need to be able to skip the beforeSave hook after update in Cloud code. |
It becomes evident that the extensibility of parse-server will be a core element of the server architecture.
Leveraging npm, it would be very simple and efficient to setup servers with custom adapters without the need of writing code.
I am personally looking for 'configuring' standalone parse-server instead of maintaining an express app that would serve the parse-server alongside the rest of my web app.
I'm opening the issue here to discuss this architecture.
I suggest the following proposal:
example:
Let's say someone implemented
parse-server-sendgrid-emailadapter
and made it available on npm.the configuration Object would look like:
in EmailAdapter:
For each adapter type, we would just have to provide the base API to conform to.
The developer of the module should provide an optional setOptions if the module support options.
For example the options for the mail adapter could be template URL's etc...
Thoughts @gfosco, @drew-gross, @nlutsenko ?
The text was updated successfully, but these errors were encountered: