Interfaces HTTP como las de Node.js ahora en Compute
Nuestra plataforma Compute, programada en JavaScript, proporciona objetos Request y Response. Sin embargo, estos se basan en el estándar de captura de datos Fetch, en lugar de en los objetos req y res que suelen manejar los programas Node.js. Si cuentas con algún programa diseñado para Node.js y tienes previsto migrarlo a Compute, o si quieres utilizar una biblioteca diseñada para Node.js, tenemos lo que necesitas: http-compute-js, nuestra nueva biblioteca de código abierto.
Node.js suele proporcionar los objetos IncomingMessage y ServerReponse, que representan, respectivamente, las peticiones enviadas a un servidor web y las respuestas provenientes de este. Sin embargo, no son equiparables a los objetos Request y Response que vienen definidos en el estándar moderno fetch y que JavaScript implementa en Compute. Aunque algunas versiones recientes de Node.js son compatibles con fetch de forma nativa, la mayoría del código Node.js no lo es.
Lo que buscamos con http-compute-js
es proporcionar a los desarrolladores objetos que tengan una interfaz compatible con Node.js que les resulte familiar. Así, tus programas o cualquier biblioteca que quieras utilizar podrán interactuar con esos objetos.
Ver para creer: objetos HTTP Node.js en Compute
Echa un vistazo a estas líneas de código:
import http from '@fastly/http-compute-js';
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!'
}));
});
server.listen();
Si no fuera por la instrucción import
del inicio, se podría decir que es un programa Node.js al uso. La función createServer acepta un controlador de eventos al que se transmite una devolución de llamadas cuyos argumentos se pueden utilizar del mismo modo que en un programa Node.js.
El objeto req
es de tipo IncomingMessage
y su interfaz de flujos, que es legible
, está vinculada al flujo del cuerpo de la petición de Compute. Este objeto se puede leer utilizando el mecanismo habitual de flujos, como on('data')
y on('end')
; canalizándolo a otro flujo, o utilizando bibliotecas como parse-body. Los encabezados y demás información también se pueden leer como en Node.js.
El objeto res
es de tipo ServerResponse y su interfaz de flujos, que es editable, está vinculada a un búfer en memoria. Este objeto se puede editar mediante res.write()
o res.end()
, o se le pueden canalizar datos mediante res.pipe()
. Los encabezados y el código de estado también se pueden configurar como en Node.js.
Todas estas funcionalidades se ven mejor en este otro ejemplo, que es un poco más específico:
import http from '@fastly/http-compute-js';
const server = http.createServer(async (req, res) => {
// Get URL, method, headers, and body from req
const url = req.url;
const method = req.method;
const headers = {};
for (let [key, value] of Object.entries(req.headers)) {
if(!Array.isArray(value)) {
value = [String(value)];
}
headers[key] = value.join(', ');
}
let body = null;
if (method !== 'GET' && method !== 'HEAD') {
// Reading data out of a stream.Readable
body = await new Promise(resolve => {
const data = [];
req.on('data', (chunk) => {
data.push(chunk);
});
req.on('end', () => {
resolve(data.join(''));
});
});
}
// Write output to res
res.setHeader('Content-Type', 'application/json');
res.statusCode = 200;
res.write(JSON.stringify({
url,
method,
headers,
body,
}));
res.end();
});
server.listen();
Observa que la devolución de llamadas transmitida a createServer
es asíncrona. Aunque la respuesta se crea tras la espera, el controlador es capaz de esperar al método res.end()
para crear un objeto Response
y enviarlo de vuelta a través del controlador de eventos fetch
subyacente de Compute.
Los polyfills ayudan a tenerlo todo en orden
Con la idea de conseguir que http-compute-js
se comporte de la manera prevista, decidimos utilizar polyfills de eficacia probada con algunas de las partes subyacentes; por ejemplo, para enviar flujos y para almacenar en búfer. Los programas de Compute escritos con JavaScript utilizan webpack para empaquetarse en web workers (trabajos web), lo que nos permite incorporar los polyfills. Así que, para poder utilizar http-compute-js
, debes realizar algunos cambios en el archivo webpack.config.js
que trae cualquier proyecto JavaScript de Compute.
Añade webpack.ProvidePlugin()
a la matriz «plugins». Además, añade los elementos siguientes a las secciones «alias» y «fallback», de modo que se creen las propiedades «resolve», «alias» y «fallback» según sea necesario.
module.exports = {
/* ...other config... */
plugins: [
new webpack.ProvidePlugin({
Buffer: [ 'buffer', 'Buffer' ],
process: 'process',
setTimeout: [ 'timeout-polyfill', 'setTimeout' ],
clearTimeout: [ 'timeout-polyfill', 'clearTimeout' ],
}),
],
resolve: {
alias: {
'timeout-polyfill': require.resolve('@fastly/http-compute-js/dist/polyfill'),
},
fallback: {
'buffer': require.resolve('buffer/'),
'process': require.resolve('process/browser'),
'stream': require.resolve('stream-browserify'),
}
},
};
Una vez definido lo anterior, los ejemplos que te hemos mostrado en este artículo funcionarán del mismo modo que lo harían en Node.js. Esperamos tener lista pronto la compatibilidad con setTimeout
en Compute, ya que nos permitiría reducir el número de polyfills.
Instalación manual de req y res
Es posible que en alguna ocasión tengas que utilizar objetos Request y Response como los de Node.js con solo algunas partes de tu programa. O que quieras realizar una llamada excepcional a una función exclusiva de Node.js. No te preocupes, está todo pensado: proporcionamos utilidades que te permiten combinar objetos Request
y Response
de Compute con los objetos equivalentes de Node.js.
/// <reference types='@fastly/js-compute' />
import { toReqRes, toComputeResponse } from '@fastly/http-compute-js';
addEventListener('fetch', (event) => event.respondWith(handleRequest(event)));
async function handleRequest(event) {
// Create Node.js-compatible req and res from event.request
const { req, res } = toReqRes(event.request);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!',
url: req.url,
}));
// Create a Compute@Edge Response object based on res, and return it
const response = await toComputeResponse(res);
return response;
}
El ejemplo anterior demuestra lo fácil que es crear objetos req
y res
compatibles con Node.js como parte de un controlador de capturas (fetch). También ilustra cómo convertirlos a objetos Response
de Compute y cómo devolverlos.
Queremos que ejecutes más código en el edge
La evolución de internet como plataforma programable no cesa, y nosotros estamos orgullosos de liderar ese proceso. Por eso, queremos que Compute siga siendo un espacio atractivo para los desarrolladores.
Sabemos que esa incesante evolución significa que todo está en cambio constante. En Fastly, nos centramos en diseñar herramientas que te permitan ejecutar más código todavía en el edge y adaptarte con más rapidez a este nuevo escenario. Y, al mismo tiempo, que te brinden una amplia gama de utilidades. Tenemos muchas ganas de saber qué creas con esta herramienta, cómo la utilizas y si empleas otras de nuestro catálogo. Si te apetece, ¡cuéntanoslo en Twitter!