Skip to content

feat: add middleware option to Parse Server config #7942

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

Open
wants to merge 50 commits into
base: alpha
Choose a base branch
from

Conversation

okobsamoht
Copy link

@okobsamoht okobsamoht commented Apr 17, 2022

New Pull Request Checklist

Issue Description

the 'middleware' option only works if parse-server is used as command line binary.
when using parse-server as an express middleware the option 'middleware' have no effect.

Approach

i uses the same condition of the middleware in ParseServer.start({...options}, callback) to let parse-server handle the middleware in ParseServer.app({...options})

TODOs before merging

  • Add tests
  • Add changes to documentation (guides, repository pages, in-code descriptions)
  • Add security check

mtrezza and others added 25 commits March 25, 2022 19:47
## [5.2.1-alpha.1](parse-community/parse-server@5.2.0...5.2.1-alpha.1) (2022-03-26)

### Bug Fixes

* return correct response when revert is used in beforeSave ([parse-community#7839](parse-community#7839)) ([f63fb2b](parse-community@f63fb2b))
## [5.2.1-alpha.2](parse-community/parse-server@5.2.1-alpha.1...5.2.1-alpha.2) (2022-03-26)

### Performance Improvements

* reduce database operations when using the constant parameter in Cloud Function validation ([parse-community#7892](parse-community#7892)) ([48bd512](parse-community@48bd512))
# [5.3.0-alpha.2](parse-community/parse-server@5.3.0-alpha.1...5.3.0-alpha.2) (2022-03-27)

### Bug Fixes

* security upgrade parse push adapter from 4.1.0 to 4.1.2 ([parse-community#7893](parse-community#7893)) ([ef56e98](parse-community@ef56e98))
# [5.3.0-alpha.4](parse-community/parse-server@5.3.0-alpha.3...5.3.0-alpha.4) (2022-04-04)

### Bug Fixes

* custom database options are not passed to MongoDB GridFS ([parse-community#7911](parse-community#7911)) ([a72b384](parse-community@a72b384))
# [5.3.0-alpha.6](parse-community/parse-server@5.3.0-alpha.5...5.3.0-alpha.6) (2022-04-11)

### Bug Fixes

* peer dependency mismatch for GraphQL dependencies ([parse-community#7934](parse-community#7934)) ([b7a1d76](parse-community@b7a1d76))
@parse-github-assistant
Copy link

parse-github-assistant bot commented Apr 17, 2022

Thanks for opening this pull request!

  • ❌ Please check all required checkboxes at the top, otherwise your pull request will be closed.

  • ⚠️ Remember that a security vulnerability must only be reported confidentially, see our Security Policy. If you are not sure whether the issue is a security vulnerability, the safest way is to treat it as such and submit it confidentially to us for evaluation.

@okobsamoht okobsamoht changed the title Alpha middleware fix feat: middleware handlling in parse-server as express middleware Apr 17, 2022
@mtrezza mtrezza requested a review from a team April 17, 2022 21:56
@mtrezza mtrezza changed the title feat: middleware handlling in parse-server as express middleware feat: add middleware option to Parse Server config Apr 17, 2022
@mtrezza mtrezza requested a review from a team May 1, 2022 23:02
@mtrezza mtrezza requested a review from dblythy May 8, 2022 14:21
@dblythy
Copy link
Member

dblythy commented May 8, 2022

Looks mostly good - might just have to fix lint and tests

@mtrezza
Copy link
Member

mtrezza commented Jun 17, 2022

@okobsamoht could you take a look at this PR to get this ready for merging?

@okobsamoht okobsamoht requested a review from mtrezza June 22, 2022 23:57
Copy link
Author

@okobsamoht okobsamoht left a comment

Choose a reason for hiding this comment

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

reviewed

@mtrezza mtrezza requested review from a team and removed request for dblythy and mtrezza June 26, 2022 09:30
@mtrezza mtrezza requested review from dblythy and removed request for a team July 2, 2022 10:21
@dblythy
Copy link
Member

dblythy commented Jul 2, 2022

Come to think of it do you really need config.middleware when using the Parse Server express constructor? Could you just use:

const app = express();
app.use(…custom middleware here)
app.use("/parse", new ParseServer(config));
app.listen(1337)

Copy link
Member

@mtrezza mtrezza left a comment

Choose a reason for hiding this comment

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

Waiting for reply to #7942 (comment)

@mtrezza mtrezza removed the request for review from dblythy July 7, 2022 09:59
@okobsamoht
Copy link
Author

Come to think of it do you really need config.middleware when using the Parse Server express constructor? Could you just use:

const app = express();
app.use(…custom middleware here)
app.use("/parse", new ParseServer(config));
app.listen(1337)

Hi @dblythy
when i do that, my custom middleware have no access to ParseServer runtime stuffs like Controllers, Adapters, Options.
and when i log req.config i always get undefined in my custom middleare.

@okobsamoht
Copy link
Author

i make this quick setup:

var express = require('express');
var ParseServer = require('parse-server').ParseServer;

var api = new ParseServer({
    appId: "APP_ID",
    appNAme: "APP_NAME",
    javascriptKey: "JAVASCRIPT_KEY",
    masterKey: "MASTER_KEY",
    directAccess: true,
    enforcePrivateUsers: true,
    port: 3000,
    mountPath: '/api',
    cloud:'cloudCode',
    middleware:(req, res, next)=>{
        console.log('parse middleware_________________________________________________________________________________')
        console.log(req.config)
        next()
    }
});

var app = express();

app.use((req, res, next)=>{
    console.log('express middleware___________________________________________________________________________________')
    console.log(req.config)
    next()
})
// parse server
app.use('/api', api);

var httpServer = require('http').createServer(app);
httpServer.listen(3000);

and each time a ran a request here is the result:

express middleware___________________________________________________________________________________
undefined
parse middleware_________________________________________________________________________________
<ref *2> Config {
  applicationId: 'APP_ID',
  appId: 'APP_ID',
  appNAme: 'APP_NAME',
  javascriptKey: 'JAVASCRIPT_KEY',
  masterKey: 'MASTER_KEY',
  directAccess: true,
  enforcePrivateUsers: true,
  port: 3000,
  mountPath: '/api',
  cloud: 'cloudCode',
  middleware: [Function: middleware],
  allowClientClassCreation: true,
  allowCustomObjectId: false,
  cacheMaxSize: 10000,
  cacheTTL: 5000,
  collectionPrefix: '',
  customPages: {},
  databaseURI: 'mongodb://localhost:27017/parse',
  emailVerifyTokenReuseIfValid: false,
  enableAnonymousUsers: true,
  enableExpressErrorHandler: false,
  expireInactiveSessions: true,
  fileUpload: {
    enableForAnonymousUser: false,
    enableForPublic: false,
    enableForAuthenticatedUser: true
  },
  graphQLPath: '/graphql',
  host: '0.0.0.0',
  idempotencyOptions: { ttl: 300, paths: [] },
  logsFolder: './logs/',
  masterKeyIps: [],
  maxUploadSize: '20mb',
  mountGraphQL: false,
  mountPlayground: false,
  objectIdSize: 10,
  pages: {
    enableRouter: false,
    enableLocalization: false,
    localizationJsonPath: undefined,
    localizationFallbackLocale: 'en',
    placeholders: {},
    forceRedirect: false,
    pagesPath: './public',
    pagesEndpoint: 'apps',
    customUrls: {},
    customRoutes: []
  },
  playgroundPath: '/playground',
  preserveFileName: false,
  preventLoginWithUnverifiedEmail: false,
  protectedFields: { _User: { '*': [Array] } },
  requestKeywordDenylist: [
    { key: '_bsontype', value: 'Code' },
    { key: 'constructor' },
    { key: '__proto__' }
  ],
  revokeSessionOnPasswordReset: true,
  scheduledPush: false,
  security: { enableCheck: false, enableCheckLog: false },
  sessionLength: 31536000,
  verifyUserEmails: false,
  jsonLogs: false,
  verbose: false,
  level: undefined,
  serverURL: 'http://localhost:3000/api',
  loggerController: LoggerController {
    options: {
      jsonLogs: false,
      logsFolder: './logs/',
      verbose: false,
      logLevel: undefined,
      silent: undefined,
      maxLogFiles: undefined
    },
    appId: 'APP_ID',
    debug: [Function (anonymous)],
    verbose: [Function (anonymous)],
    silly: [Function (anonymous)],
    [Symbol()]: WinstonLoggerAdapter {}
  },
  filesController: FilesController {
    options: { preserveFileName: false },
    appId: 'APP_ID',
    [Symbol()]: GridFSBucketAdapter {
      _databaseURI: 'mongodb://localhost:27017/parse',
      _algorithm: 'aes-256-gcm',
      _encryptionKey: null,
      _mongoOptions: [Object]
    }
  },
  userController: UserController {
    options: { verifyUserEmails: false },
    appId: 'APP_ID',
    [Symbol()]: undefined
  },
  pushController: PushController {},
  hasPushScheduledSupport: false,
  hasPushSupport: false,
  pushWorker: PushWorker {
    adapter: ParsePushAdapter {
      supportsPushTracking: true,
      validPushTypes: [Array],
      senderMap: {},
      feature: [Object]
    },
    channel: 'APP_ID-parse-server-push',
    subscriber: Consumer {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: undefined,
      emitter: [EventEmitter],
      [Symbol(kCapture)]: false
    }
  },
  pushControllerQueue: PushQueue {
    channel: 'APP_ID-parse-server-push',
    batchSize: 100,
    parsePublisher: Publisher { emitter: [EventEmitter] }
  },
  analyticsController: AnalyticsController {
    options: undefined,
    appId: undefined,
    [Symbol()]: AnalyticsAdapter {}
  },
  cacheController: <ref *1> CacheController {
    options: {},
    appId: 'APP_ID',
    role: SubCache { prefix: 'role', cache: [Circular *1], ttl: undefined },
    user: SubCache { prefix: 'user', cache: [Circular *1], ttl: undefined },
    graphQL: SubCache {
      prefix: 'graphQL',
      cache: [Circular *1],
      ttl: undefined
    },
    [Symbol()]: InMemoryCacheAdapter { cache: [LRUCache] }
  },
  parseGraphQLController: ParseGraphQLController {
    databaseController: DatabaseController {
      adapter: [MongoStorageAdapter],
      options: [Object],
      idempotencyOptions: [Object],
      _transactionalSession: null
    },
    cacheController: <ref *1> CacheController {
      options: {},
      appId: 'APP_ID',
      role: [SubCache],
      user: [SubCache],
      graphQL: [SubCache],
      [Symbol()]: [InMemoryCacheAdapter]
    },
    isMounted: false,
    configCacheKey: 'config'
  },
  liveQueryController: LiveQueryController {
    classNames: Set(0) {},
    liveQueryPublisher: ParseCloudCodePublisher { parsePublisher: [Publisher] }
  },
  database: DatabaseController {
    adapter: MongoStorageAdapter {
      _uri: 'mongodb://localhost:27017/parse',
      _collectionPrefix: '',
      _mongoOptions: [Object],
      _onchange: [Function (anonymous)],
      _maxTimeMS: undefined,
      canSortOnJoinTables: true,
      enableSchemaHooks: false,
      connectionPromise: [Promise],
      client: [MongoClient],
      database: [Db]
    },
    options: [Circular *2],
    idempotencyOptions: { ttl: 300, paths: [] },
    schemaPromise: null,
    _transactionalSession: null
  },
  hooksController: HooksController {
    _applicationId: 'APP_ID',
    _webhookKey: undefined,
    database: DatabaseController {
      adapter: [MongoStorageAdapter],
      options: [Object],
      idempotencyOptions: [Object],
      _transactionalSession: null
    }
  },
  authDataManager: {
    getValidatorForProvider: [Function: getValidatorForProvider],
    setEnableAnonymousUsers: [Function: setEnableAnonymousUsers]
  },
  schemaCache: {
    all: [Function: all],
    get: [Function: get],
    put: [Function: put],
    del: [Function: del],
    clear: [Function: clear]
  },
  _mount: 'http://127.0.0.1:3000/api',
  generateSessionExpiresAt: [Function: bound generateSessionExpiresAt],
  generateEmailVerifyTokenExpiresAt: [Function: bound generateEmailVerifyTokenExpiresAt],
  headers: {
    'user-agent': 'node-XMLHttpRequest, Parse/js1.11.1 (NodeJS 16.15.0)',
    accept: '*/*',
    'content-type': 'text/plain',
    host: '127.0.0.1:3000',
    'content-length': '146',
    connection: 'close'
  },
  ip: '::ffff:127.0.0.1'
}
express middleware___________________________________________________________________________________
undefined
parse middleware_________________________________________________________________________________
<ref *2> Config {
  applicationId: 'APP_ID',
  appId: 'APP_ID',
  appNAme: 'APP_NAME',
  javascriptKey: 'JAVASCRIPT_KEY',
.........................

@dblythy
Copy link
Member

dblythy commented Jul 10, 2022

Thanks for the explanation! I think this could be solved by #7869 - exposing the config via config.get. I think using express’ native syntax of app.use for middleware is a bit more intuitive than ParseServer.middleware and it’s easier to see the order of middleware.

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.

8 participants