diff --git a/app.js b/app.js
index b6355b95..2b8fbb86 100644
--- a/app.js
+++ b/app.js
@@ -1,11 +1,22 @@
-var app = require('express')();
-
-var peliasConfig = require( 'pelias-config' ).generate(require('./schema'));
+const app = require('express')();
+const swaggerJSDoc = require('swagger-jsdoc');
+const swaggerUi = require('express-swaggerize-ui');
+const peliasConfig = require( 'pelias-config' ).generate(require('./schema'));
if( peliasConfig.api.accessLog ){
app.use( require( './middleware/access_log' ).createAccessLogger( peliasConfig.api.accessLog ) );
}
+var swaggerSpec = swaggerJSDoc(require( './config/swagger'));
+
+
+
+app.get('/api-docs.json', function(req, res) {
+ res.setHeader('Content-Type', 'application/json');
+ res.send(swaggerSpec);
+});
+
+app.use('/api-docs', swaggerUi());
/** ----------------------- pre-processing-middleware ----------------------- **/
app.use( require('./middleware/headers') );
@@ -16,10 +27,10 @@ app.use( require('./middleware/jsonp') );
/** ----------------------- routes ----------------------- **/
-var defaultRoutes = require('./routes/default');
+const defaultRoutes = require('./routes/default');
defaultRoutes.addRoutes(app);
-var v1 = require('./routes/v1');
+const v1 = require('./routes/v1');
v1.addRoutes(app, peliasConfig);
/** ----------------------- error middleware ----------------------- **/
@@ -27,4 +38,4 @@ v1.addRoutes(app, peliasConfig);
app.use( require('./middleware/404') );
app.use( require('./middleware/500') );
-module.exports = app;
+module.exports = app;
\ No newline at end of file
diff --git a/config/swagger.js b/config/swagger.js
new file mode 100644
index 00000000..cc35e049
--- /dev/null
+++ b/config/swagger.js
@@ -0,0 +1,13 @@
+const options = {
+ 'swaggerDefinition' : {
+ 'info': {
+ 'description': 'Swagger documentation for Pelias API',
+ 'title': 'Pelias API',
+ 'version': '1.0.0'
+ }
+ },
+ 'basePath': __dirname,
+ 'apis': ['./routes/*.js']
+};
+
+module.exports = options;
\ No newline at end of file
diff --git a/package.json b/package.json
index d8bee5cb..50301b9b 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
"elasticsearch": "^15.0.0",
"elasticsearch-exceptions": "0.0.4",
"express": "^4.8.8",
+ "express-swaggerize-ui": "^1.0.2",
"geojson": "^0.5.0",
"geolib": "^2.0.18",
"iso-639-3": "^1.0.0",
@@ -64,6 +65,7 @@
"retry": "^0.12.0",
"stable": "^0.1.8",
"stats-lite": "^2.0.4",
+ "swagger-jsdoc": "^1.9.7",
"through2": "^2.0.3"
},
"devDependencies": {
diff --git a/routes/v1.js b/routes/v1.js
index 6b40f1d6..5c3625e3 100644
--- a/routes/v1.js
+++ b/routes/v1.js
@@ -402,21 +402,503 @@ function addRoutes(app, peliasConfig) {
};
- // static data endpoints
- app.get ( base, routers.index );
- app.get ( base + 'attribution', routers.attribution );
- app.get ( '/attribution', routers.attribution );
- app.get ( '/status', routers.status );
+//Models
+/**
+ * @swagger
+ * definitions:
+ * standardPeliasReturn:
+ * properties:
+ * geocoding:
+ * type: object
+ * $ref: '#/definitions/geocodingObject'
+ * type:
+ * type: string
+ * features:
+ * type: array
+ * items:
+ * $ref: '#/definitions/featureObject'
+ * bbox:
+ * type: array
+ * items: number
+ * standardPeliasErrorReturn:
+ * properties:
+ * geocoding:
+ * type: object
+ * $ref: '#/definitions/geocodingErrorObject'
+ * type:
+ * type: string
+ * features:
+ * type: array
+ * items:
+ * $ref: '#/definitions/featureObject'
+ * bbox:
+ * type: array
+ * items: number
+ * geocodingObject:
+ * properties:
+ * version:
+ * type: string
+ * attribution:
+ * type: string
+ * query:
+ * type: object
+ * engine:
+ * type: object
+ * timestamp:
+ * type: string
+ * geocodingErrorObject:
+ * properties:
+ * version:
+ * type: string
+ * attribution:
+ * type: string
+ * query:
+ * type: object
+ * errors:
+ * type: array
+ * items: string
+ * timestamp:
+ * type: string
+ * featureObject:
+ * properties:
+ * type:
+ * type: string
+ * geometry:
+ * type: object
+ * properties:
+ * type: object
+ * bbox:
+ * type: array
+ * items: number
+ * convertReturn:
+ * properties:
+ * type:
+ * type: string
+ * geometry:
+ * type: object
+ * properties:
+ * type: object
+ * $ref: '#/definitions/convertPropertiesObject'
+ * bbox:
+ * type: array
+ * items: number
+ * convertPropertiesObject:
+ * properties:
+ * from:
+ * type: string
+ * to:
+ * type: string
+ * name:
+ * type: string
+ * convertErrorReturn:
+ * properties:
+ * errors:
+ * type: string
+*/
+
+ /**
+ * @swagger
+ * /v1:
+ * get:
+ * tags:
+ * - v1
+ * operationId: v1
+ * produces:
+ * - application/json
+ * summary: Landing page
+ * responses:
+ * 200:
+ * description: 200 ok
+ * examples:
+ * application/json: { "markdown": "# Pelias API\n### Version: [1.0](https://github.com/venicegeo/pelias-api/releases)\n###
+ * [View our documentation on GitHub](https://github.com/venicegeo/pelias-documentation/blob/master/README.md)\n", "html": "
Pelias API
\n\n\n\n" }
+ */
+ app.get ( base, routers.index );
+ /**
+ * @swagger
+ * /v1/attribution:
+ * get:
+ * tags:
+ * - v1
+ * operationId: attribution
+ * produces:
+ * - application/json
+ * summary: landing page w/attribution
+ * responses:
+ * 200:
+ * description: 200 ok
+ * examples:
+ * application/json: {
+ * "markdown": "# Pelias API\n### Version: [1.0](https://github.com/venicegeo/pelias-api/releases)\n
+ * ### [View our documentation on GitHub](https://github.com/venicegeo/pelias-documentation/blob/master/README.md)\n
+ * ## Attribution\n* Geocoding by [Pelias](https://pelias.io).\n* Data from\n * [OpenStreetMap](http://www.openstreetmap.org/copyright)
+ * © OpenStreetMap contributors under [ODbL](http://opendatacommons.org/licenses/odbl/). Also see the [OSM Geocoding Guidelines]
+ * (https://wiki.osmfoundation.org/wiki/Licence/Community_Guidelines/Geocoding_-_Guideline) for acceptable use.\n
+ * * [OpenAddresses](http://openaddresses.io) under [various public-domain and share-alike licenses](http://results.openaddresses.io/)\n
+ * * [GeoNames](http://www.geonames.org/) under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)\n * [WhosOnFirst]
+ * (https://www.whosonfirst.org/) under [various CC-BY or CC-0 equivalent licenses](https://whosonfirst.org/docs/licenses/)",
+ * "html": "Pelias API
\n\nVersion:
+ * 1.0
\n\n\n\n
+ * Attribution
\n\n"
+}
+ */
+ app.get ( base + 'attribution', routers.attribution );
+ app.get ( '/attribution', routers.attribution );
+ /**
+ * @swagger
+ * /status:
+ * get:
+ * tags:
+ * - base
+ * operationId: attribution
+ * produces:
+ * - text/plain
+ * summary: Landing page w/attribution
+ * responses:
+ * 200:
+ * description: 200 ok
+ * examples:
+ * text/plain: "status: ok"
+ */
+ app.get ( '/status', routers.status );
// backend dependent endpoints
- app.get ( base + 'place', routers.place );
- app.get ( base + 'autocomplete', routers.autocomplete );
- app.get ( base + 'search', routers.search );
- app.post( base + 'search', routers.search );
- app.get ( base + 'search/structured', routers.structured );
- app.get ( base + 'reverse', routers.reverse );
- app.get ( base + 'nearby', routers.nearby );
+
+ /**
+ * @swagger
+ * /v1/place:
+ * get:
+ * tags:
+ * - v1
+ * operationId: place
+ * produces:
+ * - application/json
+ * summary: For querying specific place ID(s)
+ * parameters:
+ * - name: ids
+ * description: for details on a place returned from a previous query
+ * in: query
+ * required: true
+ * type: array
+ * items: {"type":"string", "pattern":"^[A-z]*.:[A-z]*.:[0-9]*$"}
+ *
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ */
+ app.get ( base + 'place', routers.place );
+ /**
+ * @swagger
+ * /v1/autocomplete:
+ * get:
+ * tags:
+ * - v1
+ * operationId: autocomplete
+ * summary: to give real-time result suggestions without having to type the whole location
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: text
+ * description: Text query
+ * in: query
+ * required: true
+ * type: string
+ * - name: focus.point.lat
+ * description: Focus point latitude
+ * in: query
+ * type: number
+ * - name: focus.point.lon
+ * description: Focus point longitude
+ * in: query
+ * type: number
+ * - name: boundary.rect.min_lon
+ * description: Bounding box minimum longitude
+ * in: query
+ * type: number
+ * - name: boundary.rect.max_lon
+ * description: Bounding box maximum longitude
+ * in: query
+ * type: number
+ * - name: boundary.rect.min_lat
+ * description: Bounding box minimum latitude
+ * in: query
+ * type: number
+ * - name: boundary.rect.max_lat
+ * description: Bounding box maximum latitude
+ * in: query
+ * type: number
+ * - name: sources
+ * description: Sources
+ * in: query
+ * type: string
+ * enum: [openstreetmap, openaddresses, whosonfirst, geonames]
+ * - name: layers
+ * description: Layers
+ * in: query
+ * type: string
+ * enum: [venue, address, street, country, macroregion, region, macrocounty, county, locality, localadmin, borough,
+ * neighbourhood, coarse]
+ * - name: boundary.county
+ * description: Country boundary
+ * in: query
+ * type: string
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ */
+ app.get ( base + 'autocomplete', routers.autocomplete );
+ /**
+ * @swagger
+ * /v1/search:
+ * get:
+ * tags:
+ * - v1
+ * operationId: search
+ * summary: to find a place by searching for an address or name
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: text
+ * description: Text query
+ * in: query
+ * required: true
+ * type: string
+ * - name: size
+ * description: used to limit the number of results returned.
+ * in: query
+ * type: number
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ * post:
+ * tags:
+ * - v1
+ * operationId: search
+ * summary: to find a place by searching for an address or name
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: text
+ * description: Text query
+ * in: query
+ * required: true
+ * type: string
+ * - name: size
+ * description: used to limit the number of results returned.
+ * in: query
+ * type: number
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ */
+
+ app.get ( base + 'search', routers.search );
+ app.post( base + 'search', routers.search );
+ /**
+ * @swagger
+ * /v1/search/structured:
+ * get:
+ * tags:
+ * - v1
+ * operationId: structured
+ * summary: to find a place with data already separated into housenumber, street, city, etc.
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: text
+ * description: Text query
+ * in: query
+ * required: true
+ * type: string
+ * - name: venue
+ * description: WOF Venue
+ * in: query
+ * type: string
+ * - name: address
+ * description: can contain a full address with house number or only a street name.
+ * in: query
+ * type: string
+ * - name: neighbourhood
+ * description: vernacular geographic entities that may not necessarily be official administrative divisions but are important
+ * nonetheless.
+ * in: query
+ * type: string
+ * - name: borough
+ * description: mostly known in the context of New York City, even though they may exist in other cities, such as Mexico City.
+ * in: query
+ * type: string
+ * - name: locality
+ * description: equivalent to what are commonly referred to as cities.
+ * in: query
+ * type: string
+ * - name: county
+ * description: administrative divisions between localities and regions.
+ * in: query
+ * type: string
+ * - name: region
+ * description: the first-level administrative divisions within countries, analogous to states and provinces in the United States
+ * and Canada, respectively, though most other countries contain regions as well
+ * in: query
+ * type: string
+ * - name: postalcode
+ * description: used to aid in sorting mail with the format dictated by an administrative division
+ * in: query
+ * type: string
+ * - name: country
+ * description: highest-level administrative divisions supported in a search. In addition to full names, countries have common
+ * two- and three-letter abbreviations that are also supported values for the country parameter.
+ * in: query
+ * type: string
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ */
+ app.get ( base + 'search/structured', routers.structured );
+ /**
+ * @swagger
+ * /v1/reverse:
+ * get:
+ * tags:
+ * - v1
+ * operationId: reverse
+ * summary: to find what is located at a certain coordinate location
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: point.lat
+ * description: Latitude (decimal degrees)
+ * in: query
+ * required: true
+ * type: string
+ * - name: point.lon
+ * description: Longitude (decimal degrees)
+ * in: query
+ * required: true
+ * type: string
+ * - name: boundary.circle.radius
+ * description: Bounding circle radius
+ * in: query
+ * type: number
+ * - name: size
+ * description: used to limit the number of results returned.
+ * in: query
+ * type: number
+ * - name: sources
+ * description: one or more valid source names
+ * in: query
+ * type: string
+ * enum: [openstreetmap, openaddresses, whosonfirst, geonames]
+ * - name: layers
+ * description: Layers
+ * in: query
+ * type: string
+ * enum: [venue, address, street, country, macroregion, region, macrocounty, county, locality, localadmin, borough,
+ * neighbourhood, coarse]
+ * - name: boundary.county
+ * description: Country boundary
+ * in: query
+ * type: string
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ */
+ app.get ( base + 'reverse', routers.reverse );
+ /**
+ * @swagger
+ * /v1/nearby:
+ * get:
+ * tags:
+ * - v1
+ * operationId: nearby
+ * summary: reverse geocode search including surrounding areas
+ * produces:
+ * - application/json
+ * parameters:
+ * - name: point.lat
+ * description: Latitude (decimal degrees)
+ * in: query
+ * required: true
+ * type: string
+ * - name: point.lon
+ * description: Longitude (decimal degrees)
+ * in: query
+ * required: true
+ * type: string
+ * responses:
+ * 200:
+ * description: 200 ok
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasReturn'
+ * 400:
+ * description: 400 bad request
+ * schema:
+ * type: object
+ * $ref: '#/definitions/standardPeliasErrorReturn'
+ *
+ */
+ app.get ( base + 'nearby', routers.nearby );
}
/**