koopjs / koop

Transform, query, and download geospatial data on the web.
http://koopjs.github.io
Other
659 stars 127 forks source link

Ability To Configure CORS #354

Closed joelhickok closed 1 year ago

joelhickok commented 4 years ago

Introduction:

First time playing with Koop.js, and I was able to quickly put together a mini-provider for myself that accesses a non-SDE database table in a SQL Server instance, converted to GeoJSON, and output using Koop. Awesome!

Issues quickly arise when trying to add a Koop.js endpoint to ArcGIS Online, because ArcGIS Online does not accept wildcard CORS origins (or at least this was happening in my organization). So, I added my own CORS middleware to an Express server with koop also implemented as middleware. But the cors middleware on the koop.server app was overriding my own app middleware. Can someone just make this quick fix and publish an update soon? Thanks! In the meantime, I just commented out the line in the Koop source to .use(cors()).

After commenting out the cors middleware in the koop source, this is my solution:

const corsOptions = {
    credentials: true,
    origin: function (origin, callback) {
        const value = (origin === 'https://my_org_id.maps.arcgis.com') ? origin : true
        callback(null, value)
    }
}

app.use(helmet())
    .use(cors(corsOptions))
    .use('/', koop.server)

Problem:

CORS does not work correctly out of the box with Koop.js when adding service endpoints to ArcGIS Online. For my purpose, ArcGIS Online seems to need the Access-Control-Allow-Origin header to have a single value and NOT a wildcard. Also, the Access-Control-Allow-Credentials header needs to be set to true.

Solution:

Make koop.js a little more configurable by allowing a couple more options on the config object. I am not asking for help making cors work, I am suggesting a higher-level of configuration.

Recommendations to make Koop.js more configurable:

  1. Add an override in config, same as config.disableCompression, to disable the use of CORS so that a custom middleware function can be configured when using Koop as middleware. Source code updates in koop-core/src/index.js would be simply:
    
    // .use(cors())

// Use cors middleware unless explicitly disabled in the config if (!config.disableCors) { app.use(cors()) }


2. Accept a config object for the cors middleware.

// .use(cors())

// Use cors middleware config with cors options object if (!config.disableCors) { app.use(cors(config.corsOptions)) }

joelhickok commented 4 years ago

And before this gets mentioned in the next reply, it does NOT work to simply register the cors middleware after the koop middleware, as mentioned in Issue #342 . This is why I would prefer an options object for cors setup.

I've tried numerous scenarios, and the ONLY one that works is to just get rid of the line in the koop-core source where the cors middleware gets registered. None of these example below work, until you just remove the use of the cors middleware directly on the koop.server app constructor.

Does not work:

koop.server.use(cors(config.corsOptions))
koop.server.listen(8080, () => console.log(`Koop listening on port 8080!`))

Does not work:

const app = express();
app.use('/', koop.server)
    .use(cors(config.corsOptions))
app.listen(8080)

Does not work:

const app = express();
app.use('/', cors(config.corsOptions), koop.server)
app.listen(8080)
rgwozdz commented 4 years ago

@joelhickok - thanks very much for reaching out and glad to hear you are using Koop. It seems like you have a solution worked out for configuring CORS. If you submit as a PR with the appropriate tests, I will review, merge, and publish.

I have used Koop to feed services to ArcGIS Online many times (though it has been a few months since I last did this). I've never had an issue with CORS when doing so. Just out of curiousity, where you trying to add a Koop service to a map viewer, or as an AGO item, or both? And were you using the Koop routes that include rest/services as part of url?