Skip to content

Commit 3d3fd6a

Browse files
committed
feat: set v2 as default API version; add observation search request parameter descriptions; default ignore_photos to true on observation update
1 parent cb28ac1 commit 3d3fd6a

7 files changed

Lines changed: 232 additions & 118 deletions

File tree

lib/inaturalist_api.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,12 @@ InaturalistAPI.server = async ( ) => {
247247
dfault( "get", "/v1/computervision/language_search", ComputervisionController.languageSearch );
248248
}
249249

250-
app.get( "/", routesV1.docs );
251-
app.get( "/docs", routesV1.docs );
250+
app.get( "/", routesV1.v2_docs_redirect );
251+
app.get( "/docs", routesV1.v2_docs_redirect );
252252
app.get( "/swagger.json", routesV1.swaggerRedirect );
253253
app.get( "/robots.txt", routesV1.robots );
254254

255-
app.get( "/v1", routesV1.docs );
255+
app.get( "/v1", routesV1.v1_docs_redirect );
256256
app.get( "/v1/swagger.json", routesV1.swaggerJSON );
257257
app.get( "/v1/ping", ( req, res ) => {
258258
res.setHeader( "Cache-Control",

lib/routes_v1.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ routesV1.defaultAsync = async ( method, req, res ) => {
3131
}
3232
};
3333

34-
routesV1.docs = ( req, res ) => {
34+
routesV1.v2_docs_redirect = ( req, res ) => {
35+
res.redirect( "/v2/docs" );
36+
};
37+
38+
routesV1.v1_docs_redirect = ( req, res ) => {
3539
res.redirect( "/v1/docs" );
3640
};
3741

@@ -54,7 +58,7 @@ routesV1.swaggerJSON = ( req, res ) => {
5458

5559
routesV1.robots = ( req, res ) => {
5660
res.type( "text/plain" );
57-
res.send( "User-agent: *\nAllow: /v1/docs\nDisallow: /" );
61+
res.send( "User-agent: *\nAllow: /v1/docs\nAllow: /v2/docs\nDisallow: /" );
5862
};
5963

6064
module.exports = routesV1;

openapi/doc.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fs.readdirSync( "./openapi/schema/request" ).forEach( file => {
2929

3030
const parsedUrl = nodeUrl.parse( config.currentVersionURL );
3131
const url = `${parsedUrl.protocol}//${parsedUrl.host}/v2`;
32+
const schemaUrl = `${parsedUrl.protocol}//${parsedUrl.host}/v2/api-docs`;
3233
const risonUrl = `${url}/observations?fields=(species_guess:!t,user:(login:!t))`;
3334

3435
const apiDoc = {
@@ -37,10 +38,10 @@ const apiDoc = {
3738
url
3839
}],
3940
info: {
40-
title: "Test iNaturalist Version 2 API",
41-
version: "2.0.0-alpha",
41+
title: "iNaturalist Version 2 API",
42+
version: "2.2.0",
4243
description: `## ${url}
43-
**UNDER ACTIVE DEVELOPMENT, USE OF THIS ALPHA RELEASE NOT RECOMMENDED**
44+
The OpenAPI 3.0 schema definition of this API is available at <${schemaUrl}>.
4445
4546
These API methods return data in JSON/JSONP and PNG response formats. Visit our
4647
[developers page](https://www.inaturalist.org/pages/developers) for more
@@ -96,7 +97,7 @@ a URL-friendly variant of JSON. If you want to request fields like
9697
9798
you can encode those fields as RISON:
9899
99-
<a href="${risonUrl}">${risonUrl}</a>
100+
<${risonUrl}>
100101
101102
This is our preferred way to specify fields because it maintains the caching
102103
benefits of URLs that are unique to their responses, and it avoids the

openapi/schema/request/observations_search.js

Lines changed: 185 additions & 102 deletions
Large diffs are not rendered by default.

openapi/schema/request/observations_update.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ const Joi = require( "joi" );
22

33
module.exports = Joi.object( ).keys( {
44
fields: Joi.any( ),
5-
ignore_photos: Joi.boolean( ),
5+
ignore_photos: Joi.boolean( )
6+
.default( true )
7+
.description( "**NOTE: if `ignore_photos` is set to false, all photos will be removed from the observation**" ),
68
observation: Joi.object( ).keys( {
79
uuid: Joi.string( ).guid( { version: "uuidv4" } ),
810
captive_flag: Joi.boolean( ),

test/integration/v1/basic.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ const request = require( "supertest" );
33

44
describe( "routes", ( ) => {
55
describe( "index", ( ) => {
6-
it( "redirects to /v1/docs", function ( done ) {
6+
it( "redirects to /v2/docs", function ( done ) {
77
request( this.app ).get( "/" )
8-
.expect( "Location", "/v1/docs", done );
8+
.expect( "Location", "/v2/docs", done );
99
} );
1010
} );
1111

1212
describe( "docs", ( ) => {
13-
it( "redirects to /v1/docs", function ( done ) {
13+
it( "redirects to /v2/docs", function ( done ) {
1414
request( this.app ).get( "/docs" )
15-
.expect( "Location", "/v1/docs", done );
15+
.expect( "Location", "/v2/docs", done );
1616
} );
1717
} );
1818

@@ -39,7 +39,7 @@ describe( "routes", ( ) => {
3939
it( "renders a robots.txt file", function ( done ) {
4040
request( this.app ).get( "/robots.txt" )
4141
.expect( res => {
42-
expect( res.text ).to.eq( "User-agent: *\nAllow: /v1/docs\nDisallow: /" );
42+
expect( res.text ).to.eq( "User-agent: *\nAllow: /v1/docs\nAllow: /v2/docs\nDisallow: /" );
4343
} ).expect( "Content-Type", /plain/ )
4444
.expect( 200, done );
4545
} );

test/integration/v2/observations.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ describe( "Observations", ( ) => {
857857
// controller will load fresh data from the ES index, so if we want to see
858858
// a change without actually changing data, we need to stub the v1
859859
// controller reponse
860-
sinon.stub( ObservationsController, "update" )
860+
const stub = sinon.stub( ObservationsController, "update" )
861861
.callsFake(
862862
( ) => ( { ...fixtureObs, description: newDesc } )
863863
);
@@ -869,10 +869,34 @@ describe( "Observations", ( ) => {
869869
.expect( res => {
870870
expect( res.body.results[0].uuid ).to.eq( fixtureObs.uuid );
871871
expect( res.body.results[0].description ).to.eq( newDesc );
872+
stub.restore( );
872873
} )
873874
.expect( "Content-Type", /json/ )
874875
.expect( 200, done );
875876
} );
877+
878+
it( "defaults ignore_photos to true", function ( done ) {
879+
nock( "http://localhost:3000" )
880+
.put( `/observations/${fixtureObs.uuid}`, JSON.stringify( { ignore_photos: true } ) )
881+
.reply( 200, [{ id: fixtureObs.id, uuid: fixtureObs.uuid }] );
882+
request( this.app ).put( `/v2/observations/${fixtureObs.uuid}` )
883+
.set( "Authorization", token )
884+
.set( "Content-Type", "application/json" )
885+
.expect( 200, done );
886+
} );
887+
888+
it( "can set ignore_photos to false", function ( done ) {
889+
nock( "http://localhost:3000" )
890+
.put( `/observations/${fixtureObs.uuid}`, JSON.stringify( { ignore_photos: false } ) )
891+
.reply( 200, [{ id: fixtureObs.id, uuid: fixtureObs.uuid }] );
892+
request( this.app ).put( `/v2/observations/${fixtureObs.uuid}` )
893+
.send( {
894+
ignore_photos: false
895+
} )
896+
.set( "Authorization", token )
897+
.set( "Content-Type", "application/json" )
898+
.expect( 200, done );
899+
} );
876900
} );
877901

878902
describe( "delete", ( ) => {

0 commit comments

Comments
 (0)