2020-09-14 13:33:37 +03:00
|
|
|
const url = require('url');
|
2022-08-11 17:42:21 +03:00
|
|
|
const debug = require('@tryghost/debug')('http');
|
2022-08-11 17:29:08 +03:00
|
|
|
|
2023-05-02 23:43:47 +03:00
|
|
|
const Frame = require('./Frame');
|
2022-08-11 17:29:08 +03:00
|
|
|
const headers = require('./headers');
|
2018-10-05 01:50:45 +03:00
|
|
|
|
2019-05-06 15:24:12 +03:00
|
|
|
/**
|
|
|
|
* @description HTTP wrapper.
|
|
|
|
*
|
|
|
|
* This wrapper is used in the routes definition (see web/).
|
|
|
|
* The wrapper receives the express request, prepares the frame and forwards the request to the pipeline.
|
|
|
|
*
|
|
|
|
* @param {Function} apiImpl - Pipeline wrapper, which executes the target ctrl function.
|
|
|
|
* @return {Function}
|
|
|
|
*/
|
2019-02-25 21:52:45 +03:00
|
|
|
const http = (apiImpl) => {
|
2022-04-06 09:48:30 +03:00
|
|
|
return async (req, res, next) => {
|
2019-10-15 17:07:38 +03:00
|
|
|
debug(`External API request to ${req.url}`);
|
2019-01-24 17:19:34 +03:00
|
|
|
let apiKey = null;
|
|
|
|
let integration = null;
|
|
|
|
let user = null;
|
|
|
|
|
|
|
|
if (req.api_key) {
|
|
|
|
apiKey = {
|
|
|
|
id: req.api_key.get('id'),
|
|
|
|
type: req.api_key.get('type')
|
|
|
|
};
|
2019-02-06 22:11:44 +03:00
|
|
|
integration = {
|
|
|
|
id: req.api_key.get('integration_id')
|
|
|
|
};
|
2019-01-24 17:19:34 +03:00
|
|
|
}
|
|
|
|
|
2022-08-12 09:46:32 +03:00
|
|
|
if (req.user?.id) {
|
2019-01-24 17:19:34 +03:00
|
|
|
user = req.user.id;
|
|
|
|
}
|
|
|
|
|
2022-08-11 17:29:08 +03:00
|
|
|
const frame = new Frame({
|
2018-10-05 01:50:45 +03:00
|
|
|
body: req.body,
|
|
|
|
file: req.file,
|
|
|
|
files: req.files,
|
|
|
|
query: req.query,
|
|
|
|
params: req.params,
|
|
|
|
user: req.user,
|
2020-03-05 13:22:32 +03:00
|
|
|
session: req.session,
|
2020-09-14 13:33:37 +03:00
|
|
|
url: {
|
|
|
|
host: req.vhost ? req.vhost.host : req.get('host'),
|
|
|
|
pathname: url.parse(req.originalUrl || req.url).pathname,
|
|
|
|
secure: req.secure
|
|
|
|
},
|
2018-10-05 01:50:45 +03:00
|
|
|
context: {
|
2019-01-24 17:19:34 +03:00
|
|
|
api_key: apiKey,
|
|
|
|
user: user,
|
|
|
|
integration: integration,
|
2018-11-07 14:01:27 +03:00
|
|
|
member: (req.member || null)
|
2019-02-25 21:52:45 +03:00
|
|
|
}
|
2018-10-05 01:50:45 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
frame.configure({
|
|
|
|
options: apiImpl.options,
|
|
|
|
data: apiImpl.data
|
|
|
|
});
|
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
try {
|
|
|
|
const result = await apiImpl(frame);
|
2018-10-05 01:50:45 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
debug(`External API request to ${frame.docName}.${frame.method}`);
|
|
|
|
|
|
|
|
// CASE: api ctrl wants to handle the express response (e.g. streams)
|
|
|
|
if (typeof result === 'function') {
|
|
|
|
debug('ctrl function call');
|
|
|
|
return result(req, res, next);
|
|
|
|
}
|
2018-10-12 20:44:01 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
let statusCode = 200;
|
|
|
|
if (typeof apiImpl.statusCode === 'function') {
|
|
|
|
statusCode = apiImpl.statusCode(result);
|
|
|
|
} else if (apiImpl.statusCode) {
|
|
|
|
statusCode = apiImpl.statusCode;
|
|
|
|
}
|
2018-10-05 01:50:45 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
res.status(statusCode);
|
2018-10-05 01:50:45 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
// CASE: generate headers based on the api ctrl configuration
|
2022-08-12 09:12:35 +03:00
|
|
|
const apiHeaders = await headers.get(result, apiImpl.headers, frame) || {};
|
2022-08-11 17:29:08 +03:00
|
|
|
res.set(apiHeaders);
|
2020-11-04 02:08:32 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
const send = (format) => {
|
|
|
|
if (format === 'plain') {
|
|
|
|
debug('plain text response');
|
|
|
|
return res.send(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
debug('json response');
|
|
|
|
res.json(result || {});
|
|
|
|
};
|
2020-11-04 02:08:32 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
let responseFormat;
|
2020-11-04 02:08:32 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
if (apiImpl.response){
|
|
|
|
if (typeof apiImpl.response.format === 'function') {
|
|
|
|
const apiResponseFormat = apiImpl.response.format();
|
2020-11-04 02:08:32 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
if (apiResponseFormat.then) { // is promise
|
|
|
|
return apiResponseFormat.then((formatName) => {
|
|
|
|
send(formatName);
|
|
|
|
});
|
2020-11-04 02:08:32 +03:00
|
|
|
} else {
|
2022-04-06 09:48:30 +03:00
|
|
|
responseFormat = apiResponseFormat;
|
2020-11-04 02:08:32 +03:00
|
|
|
}
|
2022-04-06 09:48:30 +03:00
|
|
|
} else {
|
|
|
|
responseFormat = apiImpl.response.format;
|
2018-10-05 01:50:45 +03:00
|
|
|
}
|
2022-04-06 09:48:30 +03:00
|
|
|
}
|
2018-10-05 01:50:45 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
send(responseFormat);
|
|
|
|
} catch (err) {
|
|
|
|
req.frameOptions = {
|
|
|
|
docName: frame.docName,
|
|
|
|
method: frame.method
|
|
|
|
};
|
2019-02-25 21:11:16 +03:00
|
|
|
|
2022-04-06 09:48:30 +03:00
|
|
|
next(err);
|
|
|
|
}
|
2018-10-05 01:50:45 +03:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = http;
|