Skip to content

Commit

Permalink
Add OPTIONS support for dataset and narrative endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
tsibley committed Jun 23, 2023
1 parent 0c9d6cb commit bb83c4b
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 28 deletions.
57 changes: 31 additions & 26 deletions docs/api-restful.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ Authentication
Authentication is required for:

1. All resource-modifying requests (PUT, DELETE).
2. Read-only requests (GET, HEAD) to private resources (e.g. private `Nextstrain
Groups`_).
2. Read-only requests (GET, HEAD, OPTIONS) to private resources (e.g. private
`Nextstrain Groups`_).
3. All requests to group settings endpoints.

Authentication is not required to download public datasets or narratives.
Expand Down Expand Up @@ -232,6 +232,11 @@ DELETE
Removes all representations of the resource identified by the request URL.
Responds with status 204 if successful.

OPTIONS
Lists the methods, via the ``Allow`` header, that the authenticated user
(if any) is authorized to use on the resource identified by the request
URL. Responds with status 204 is successful.


Conditional requests
====================
Expand All @@ -248,45 +253,45 @@ Endpoints

The following dataset endpoints exist::

{GET, HEAD, PUT, DELETE} /dengue/*
{GET, HEAD, PUT, DELETE} /ebola/*
{GET, HEAD, PUT, DELETE} /enterovirus/*
{GET, HEAD, PUT, DELETE} /flu/*
{GET, HEAD, PUT, DELETE} /lassa/*
{GET, HEAD, PUT, DELETE} /measles/*
{GET, HEAD, PUT, DELETE} /mers/*
{GET, HEAD, PUT, DELETE} /mumps/*
{GET, HEAD, PUT, DELETE} /ncov/*
{GET, HEAD, PUT, DELETE} /tb/*
{GET, HEAD, PUT, DELETE} /WNV/*
{GET, HEAD, PUT, DELETE} /yellow-fever/*
{GET, HEAD, PUT, DELETE} /zika/*
{GET, HEAD, PUT, DELETE, OPTIONS} /dengue/*
{GET, HEAD, PUT, DELETE, OPTIONS} /ebola/*
{GET, HEAD, PUT, DELETE, OPTIONS} /enterovirus/*
{GET, HEAD, PUT, DELETE, OPTIONS} /flu/*
{GET, HEAD, PUT, DELETE, OPTIONS} /lassa/*
{GET, HEAD, PUT, DELETE, OPTIONS} /measles/*
{GET, HEAD, PUT, DELETE, OPTIONS} /mers/*
{GET, HEAD, PUT, DELETE, OPTIONS} /mumps/*
{GET, HEAD, PUT, DELETE, OPTIONS} /ncov/*
{GET, HEAD, PUT, DELETE, OPTIONS} /tb/*
{GET, HEAD, PUT, DELETE, OPTIONS} /WNV/*
{GET, HEAD, PUT, DELETE, OPTIONS} /yellow-fever/*
{GET, HEAD, PUT, DELETE, OPTIONS} /zika/*

{GET, HEAD, PUT, DELETE} /staging/*
{GET, HEAD, PUT, DELETE, OPTIONS} /staging/*

{GET, HEAD, PUT, DELETE} /groups/{name}/*
{GET, HEAD, PUT, DELETE, OPTIONS} /groups/{name}/*

{GET, HEAD} /community/{user}/{repo}/*
{GET, HEAD, OPTIONS} /community/{user}/{repo}/*

{GET, HEAD} /fetch/*
{GET, HEAD, OPTIONS} /fetch/*

The following narrative endpoints exist::

{GET, HEAD, PUT, DELETE} /narratives/*
{GET, HEAD, PUT, DELETE, OPTIONS} /narratives/*

{GET, HEAD, PUT, DELETE} /staging/narratives/*
{GET, HEAD, PUT, DELETE, OPTIONS} /staging/narratives/*

{GET, HEAD, PUT, DELETE} /groups/{name}/narratives/*
{GET, HEAD, PUT, DELETE, OPTIONS} /groups/{name}/narratives/*

{GET, HEAD} /community/narratives/{user}/{repo}/*
{GET, HEAD, OPTIONS} /community/narratives/{user}/{repo}/*

{GET, HEAD} /fetch/narratives/*
{GET, HEAD, OPTIONS} /fetch/narratives/*

The following group settings endpoints exist::

{GET, HEAD, PUT, DELETE} /groups/{name}/settings/logo
{GET, HEAD, PUT, DELETE, OPTIONS} /groups/{name}/settings/logo

{GET, HEAD, PUT, DELETE} /groups/{name}/settings/overview
{GET, HEAD, PUT, DELETE, OPTIONS} /groups/{name}/settings/overview

.. _motivation:

Expand Down
17 changes: 15 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@ const {
getDataset,
putDataset,
deleteDataset,
optionsDataset,
getNarrative,
putNarrative,
deleteNarrative,
optionsNarrative,
} = endpoints.sources;

const {
optionsGroup,
getGroupLogo,
putGroupLogo,
deleteGroupLogo,
Expand Down Expand Up @@ -211,13 +214,15 @@ app.routeAsync(coreBuildRoutes)
.getAsync(getDataset)
.putAsync(putDataset)
.deleteAsync(deleteDataset)
.optionsAsync(optionsDataset)
;

app.routeAsync("/narratives/*")
.all(setNarrative(req => req.params[0]))
.getAsync(getNarrative)
.putAsync(putNarrative)
.deleteAsync(deleteNarrative)
.optionsAsync(optionsNarrative)
;


Expand All @@ -237,13 +242,15 @@ app.routeAsync("/staging/narratives/*")
.getAsync(getNarrative)
.putAsync(putNarrative)
.deleteAsync(deleteNarrative)
.optionsAsync(optionsNarrative)
;

app.routeAsync("/staging/*")
.all(setDataset(req => req.params[0]), canonicalizeDataset(path => `/staging/${path}`))
.getAsync(getDataset)
.putAsync(putDataset)
.deleteAsync(deleteDataset)
.optionsAsync(optionsDataset)
;


Expand All @@ -267,11 +274,13 @@ app.use(["/community/narratives/:user/:repo", "/community/:user/:repo"],
app.routeAsync(["/community/narratives/:user/:repo", "/community/narratives/:user/:repo/*"])
.all(setNarrative(req => req.params[0]))
.getAsync(getNarrative)
.optionsAsync(optionsNarrative)
;

app.routeAsync(["/community/:user/:repo", "/community/:user/:repo/*"])
.all(setDataset(req => req.params[0]))
.getAsync(getDataset)
.optionsAsync(optionsDataset)
;


Expand All @@ -283,11 +292,13 @@ app.use(["/fetch/narratives/:authority", "/fetch/:authority"],
app.routeAsync("/fetch/narratives/:authority/*")
.all(setNarrative(req => req.params[0]))
.getAsync(getNarrative)
.optionsAsync(optionsNarrative)
;

app.routeAsync("/fetch/:authority/*")
.all(setDataset(req => req.params[0]))
.getAsync(getDataset)
.optionsAsync(optionsDataset)
;


Expand Down Expand Up @@ -326,14 +337,14 @@ app.routeAsync("/groups/:groupName/settings/logo")
.getAsync(getGroupLogo)
.putAsync(putGroupLogo)
.deleteAsync(deleteGroupLogo)
.optionsAsync(endpoints.options.forAuthzObject(req => req.context.group))
.optionsAsync(optionsGroup)
;

app.routeAsync("/groups/:groupName/settings/overview")
.getAsync(getGroupOverview)
.putAsync(putGroupOverview)
.deleteAsync(deleteGroupOverview)
.optionsAsync(endpoints.options.forAuthzObject(req => req.context.group))
.optionsAsync(optionsGroup)
;

app.route("/groups/:groupName/settings/*")
Expand All @@ -348,13 +359,15 @@ app.routeAsync("/groups/:groupName/narratives/*")
.getAsync(getNarrative)
.putAsync(putNarrative)
.deleteAsync(deleteNarrative)
.optionsAsync(optionsNarrative)
;

app.routeAsync("/groups/:groupName/*")
.all(setDataset(req => req.params[0]))
.getAsync(getDataset)
.putAsync(putDataset)
.deleteAsync(deleteDataset)
.optionsAsync(optionsDataset)
;


Expand Down
4 changes: 4 additions & 0 deletions src/endpoints/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as authz from "../authz/index.js";
import { Group } from "../groups.js";
import {contentTypesProvided, contentTypesConsumed} from "../negotiate.js";
import {deleteByUrls, proxyFromUpstream, proxyToUpstream} from "../upstream.js";
import * as options from "./options.js";


const setGroup = (nameExtractor) => (req, res, next) => {
Expand All @@ -17,6 +18,8 @@ const setGroup = (nameExtractor) => (req, res, next) => {
/* Group customizations
*/

const optionsGroup = options.forAuthzObject(req => req.context.group);


/* Group logo
*/
Expand Down Expand Up @@ -151,6 +154,7 @@ async function receiveGroupLogo(req, res) {

export {
setGroup,
optionsGroup,
getGroupLogo,
putGroupLogo,
deleteGroupLogo,
Expand Down
9 changes: 9 additions & 0 deletions src/endpoints/sources.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { NotFound } from '../httpErrors.js';

import * as authz from '../authz/index.js';
import { contentTypesProvided, contentTypesConsumed } from '../negotiate.js';
import * as options from './options.js';
import { sendAuspiceEntrypoint } from './static.js';
import { deleteByUrls, proxyFromUpstream, proxyToUpstream } from "../upstream.js";

Expand Down Expand Up @@ -177,6 +178,12 @@ const deleteDataset = deleteResource(req => req.context.dataset);
const deleteNarrative = deleteResource(req => req.context.narrative);


/* OPTIONS
*/
const optionsDataset = options.forAuthzObject(req => req.context.dataset);
const optionsNarrative = options.forAuthzObject(req => req.context.narrative);


/* Narratives
*/

Expand Down Expand Up @@ -395,12 +402,14 @@ export {
getDataset,
putDataset,
deleteDataset,
optionsDataset,

setNarrative,
ifNarrativeExists,
getNarrative,
putNarrative,
deleteNarrative,
optionsNarrative,

sendDatasetSubresource,
sendNarrativeSubresource,
Expand Down

0 comments on commit bb83c4b

Please sign in to comment.