Cscott has uploaded a new change for review.
https://gerrit.wikimedia.org/r/233107
Change subject: WIP: Implement Parsoid v3 API
......................................................................
WIP: Implement Parsoid v3 API
Everything's done except the new semantics of the 'bodyOnly' parameter.
Completely untested.
Bug: T100680
Change-Id: I90f584c23e7057e278e7bf05039beaccd298532d
---
M api/ParsoidService.js
M api/routes.js
M api/utils.js
3 files changed, 67 insertions(+), 39 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/parsoid
refs/changes/07/233107/1
diff --git a/api/ParsoidService.js b/api/ParsoidService.js
index b4b4a7e..d77c50c 100644
--- a/api/ParsoidService.js
+++ b/api/ParsoidService.js
@@ -116,9 +116,10 @@
// Routes
- var i = routes.interParams;
var p = routes.parserEnvMw;
- var v = routes.v2Middle;
+ var v1 = routes.v1Middle;
+ var v2 = routes.v2Middle;
+ var v3 = routes.v3Middle;
function re(str) { return new RegExp(str); }
@@ -130,22 +131,25 @@
app.get('/robots.txt', routes.robots);
// private routes
- app.get(re('^/_html/(?:(' + mwApiRe + ')/(.*))?'), i, p,
routes.html2wtForm);
- app.get(re('^/_wikitext/(?:(' + mwApiRe + ')/(.*))?'), i, p,
routes.wt2htmlForm);
- app.get(re('^/_rt/(?:(' + mwApiRe + ')/(.*))?'), i, p,
routes.roundtripTesting);
- app.get(re('^/_rtve/(' + mwApiRe + ')/(.*)'), i, p,
routes.roundtripTestingNL);
- app.get(re('^/_rtselser/(' + mwApiRe + ')/(.*)'), i, p,
routes.roundtripSelser);
- app.get(re('^/_rtform/(?:(' + mwApiRe + ')/(.*))?'), i, p,
routes.getRtForm);
- app.post(re('^/_rtform/(?:(' + mwApiRe + ')/(.*))?'), i, p,
routes.postRtForm);
+ app.get(re('^/_html/(?:(' + mwApiRe + ')/(.*))?'), v1, p,
routes.html2wtForm);
+ app.get(re('^/_wikitext/(?:(' + mwApiRe + ')/(.*))?'), v1, p,
routes.wt2htmlForm);
+ app.get(re('^/_rt/(?:(' + mwApiRe + ')/(.*))?'), v1, p,
routes.roundtripTesting);
+ app.get(re('^/_rtve/(' + mwApiRe + ')/(.*)'), v1, p,
routes.roundtripTestingNL);
+ app.get(re('^/_rtselser/(' + mwApiRe + ')/(.*)'), v1, p,
routes.roundtripSelser);
+ app.get(re('^/_rtform/(?:(' + mwApiRe + ')/(.*))?'), v1, p,
routes.getRtForm);
+ app.post(re('^/_rtform/(?:(' + mwApiRe + ')/(.*))?'), v1, p,
routes.postRtForm);
// v1 API routes
- app.get(re('^/(' + mwApiRe + ')/(.*)'), i, p, routes.v1Get);
- app.post(re('^/(' + mwApiRe + ')/(.*)'), i, p, routes.v1Post);
+ app.get(re('^/(' + mwApiRe + ')/(.*)'), v1, p, routes.v1Get);
+ app.post(re('^/(' + mwApiRe + ')/(.*)'), v1, p, routes.v1Post);
// v2 API routes
- app.get('/v2/:domain/:format/:title/:revision?', v, p, routes.v2Get);
- app.post('/v2/:domain/:format/:title?/:revision?', v, p, routes.v2Post);
+ app.get('/v2/:domain/:format/:title/:revision?', v2, p, routes.v2Get);
+ app.post('/v2/:domain/:format/:title?/:revision?', v2, p,
routes.v2Post);
+ // v3 API routes
+ app.get('/:domain/v3/:format/:title/:revision?', v3, p, routes.v3Get);
+ app.post('/:domain/v3/transform/:from/to/:format/:title?/:revision?',
v3, p, routes.v3Post);
// Get host and port from the environment, if available
var port = parsoidConfig.serverPort || process.env.PORT || 8000;
diff --git a/api/routes.js b/api/routes.js
index 733b2c1..f574ced 100644
--- a/api/routes.js
+++ b/api/routes.js
@@ -25,21 +25,22 @@
// Middlewares
- routes.interParams = function(req, res, next) {
+ routes.v1Middle = function(req, res, next) {
res.locals.iwp = req.params[0] || parsoidConfig.defaultWiki ||
'';
res.locals.pageName = req.params[1] || '';
res.locals.oldid = req.body.oldid || req.query.oldid || null;
// "body" flag to return just the body (instead of the entire
HTML doc)
- res.locals.body = !!(req.query.body || req.body.body);
+ res.locals.bodyOnly = !!(req.query.body || req.body.body);
// "subst" flag to perform {{subst:}} template expansion
res.locals.subst = !!(req.query.subst || req.body.subst);
next();
};
var wt2htmlFormats = new Set(['pagebundle', 'html']);
- var supportedFormats = new Set(['pagebundle', 'html', 'wt']);
+ var v2SupportedFormats = new Set(['pagebundle', 'html', 'wt']);
+ var v3SupportedFormats = new Set(['pagebundle', 'html', 'wikitext']);
- routes.v2Middle = function(req, res, next) {
+ routes.v23Middle = function(version, req, res, next) {
function errOut(err, code) {
apiUtils.sendResponse(res, {}, err, code || 404);
}
@@ -52,26 +53,39 @@
res.locals.iwp = iwp;
res.locals.pageName = req.params.title || '';
res.locals.oldid = req.params.revision || null;
+ res.locals.apiVersion = version;
- // "body" flag to return just the body (instead of the entire
HTML doc)
- res.locals.body = !!(req.query.body || req.body.body);
+ // "bodyOnly" flag to return just the body (instead of the
entire HTML doc)
+ if (version > 2) {
+ res.locals.bodyOnly = !!(req.query.bodyOnly ||
req.body.bodyOnly);
+ } else {
+ // in v2 this flag was named "body"
+ res.locals.bodyOnly = !!(req.query.body ||
req.body.body);
+ }
- var v2 = Object.assign({ format: req.params.format }, req.body);
+ var v23 = Object.assign({ format: req.params.format },
req.body);
+ var supportedFormats = (version > 2) ?
+ v3SupportedFormats : v2SupportedFormats;
- if (!supportedFormats.has(v2.format) ||
- (req.method === 'GET' &&
!wt2htmlFormats.has(v2.format))) {
- return errOut('Invalid format.');
+ if (!supportedFormats.has(v23.format) ||
+ (req.method === 'GET' &&
!wt2htmlFormats.has(v23.format))) {
+ return errOut('Invalid format: ' + v23.format);
+ }
+
+ // In v2 the "wikitext" format was named "wt"
+ if (v23.format === 'wt') {
+ v23.format === 'wikitext';
}
// "subst" flag to perform {{subst:}} template expansion
res.locals.subst = !!(req.query.subst || req.body.subst);
// This is only supported for the html format
- if (res.locals.subst && v2.format !== 'html') {
+ if (res.locals.subst && v23.format !== 'html') {
return errOut('Substitution is only supported for the
HTML format.', 501);
}
if (req.method === 'POST') {
- var original = v2.original || {};
+ var original = v23.original || {};
if (original.revid) {
res.locals.oldid = original.revid;
}
@@ -80,9 +94,11 @@
}
}
- res.locals.v2 = v2;
+ res.locals.v23 = v23;
next();
};
+ routes.v2Middle = routes.v23Middle.bind(routes, 2);
+ routes.v3Middle = routes.v23Middle.bind(routes, 3);
routes.parserEnvMw = function(req, res, next) {
function errBack(env, logData, callback) {
@@ -116,7 +132,7 @@
apiUtils.setHeader(res, env,
'Access-Control-Allow-Origin',
env.conf.parsoid.allowCORS);
}
- if (res.locals.v2 && res.locals.v2.format ===
'pagebundle') {
+ if (res.locals.v23 && res.locals.v23.format ===
'pagebundle') {
env.storeDataParsoid = true;
}
if (req.body.hasOwnProperty('scrubWikitext')) {
@@ -419,7 +435,7 @@
var v2Wt2html = function(req, res, wt) {
var env = res.locals.env;
- var v2 = res.locals.v2;
+ var v2 = res.locals.v23;
var p = apiUtils.startWt2html(req, res, wt).then(function(ret) {
if (typeof ret.wikitext === 'string') {
return apiUtils.parseWt(ret)
@@ -478,13 +494,13 @@
};
// GET requests
- routes.v2Get = function(req, res) {
+ routes.v2Get = routes.v3Get = function(req, res) {
return v2Wt2html(req, res);
};
// POST requests
- routes.v2Post = function(req, res) {
- var v2 = res.locals.v2;
+ routes.v2Post = routes.v3Post = function(req, res) {
+ var v2 = res.locals.v23;
var env = res.locals.env;
function errOut(err, code) {
@@ -538,12 +554,18 @@
}
return ret;
}).then(apiUtils.endHtml2wt).then(function(output) {
- apiUtils.jsonResponse(res, env, {
- wikitext: {
- headers: { 'content-type':
apiUtils.WIKITEXT_CONTENT_TYPE },
- body: output,
- },
- });
+ if (res.locals.apiVersion > 2) {
+ apiUtils.setHeader(res, env,
'content-type', apiUtils.WIKITEXT_CONTENT_TYPE);
+ apiUtils.sendResponse(res, env, output);
+ } else {
+ // In API v2 we used to send a JSON
object here
+ apiUtils.jsonResponse(res, env, {
+ wikitext: {
+ headers: {
'content-type': apiUtils.WIKITEXT_CONTENT_TYPE },
+ body: output,
+ },
+ });
+ }
});
return apiUtils.cpuTimeout(p, res)
.catch(apiUtils.timeoutResp.bind(null, env));
diff --git a/api/utils.js b/api/utils.js
index 55cf3d3..62bc595 100644
--- a/api/utils.js
+++ b/api/utils.js
@@ -490,7 +490,8 @@
var startTimers = ret.startTimers;
if (doc) {
- output = DU.serializeNode(res.locals.body ? doc.body : doc).str;
+ // XXX in v3 api, should be just the children of the body
+ output = DU.serializeNode(res.locals.bodyOnly ? doc.body :
doc).str;
apiUtils.setHeader(res, env, 'content-type',
apiUtils.HTML_CONTENT_TYPE);
apiUtils.endResponse(res, env, output);
}
@@ -517,7 +518,8 @@
var res = ret.res;
var v2 = res.locals.v2;
if (v2.format === 'pagebundle') {
- var out = DU.extractDpAndSerialize(doc, res.locals.body);
+ // XXX in v3 api, should be just the children of the body
+ var out = DU.extractDpAndSerialize(doc, res.locals.bodyOnly);
apiUtils.jsonResponse(res, env, {
html: {
headers: { 'content-type':
apiUtils.HTML_CONTENT_TYPE },
--
To view, visit https://gerrit.wikimedia.org/r/233107
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I90f584c23e7057e278e7bf05039beaccd298532d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/services/parsoid
Gerrit-Branch: master
Gerrit-Owner: Cscott <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits