diff --git a/src/app.ts b/src/app.ts index b999a1a7..bcb5cfc2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -60,10 +60,7 @@ const start = (options = {}): FastifyInstance => { }); // proxies - if (config.mithril.enabled) { - console.log(`Mithril proxy enabled. Aggregator: ${config.mithril.aggregator}.`); - registerMithrilProxy(app); - } + registerMithrilProxy(app); // addresses registerRoute(app, import('./routes/addresses/address/extended.js')); diff --git a/src/proxies/mithril.ts b/src/proxies/mithril.ts index 70325a93..b7166a00 100644 --- a/src/proxies/mithril.ts +++ b/src/proxies/mithril.ts @@ -1,13 +1,20 @@ import fastifyHttpProxy from '@fastify/http-proxy'; import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; import { getConfig } from '../config.js'; -import { handle404, handle500 } from '../utils/error-handler.js'; +import { handle500 } from '../utils/error-handler.js'; import { convertStreamToString } from '@blockfrost/blockfrost-utils/lib/fastify.js'; import { matchUrlToEndpoint } from '../utils/string-utils.js'; import { appendLocationToSnapshot } from '../utils/mithril.js'; export const registerMithrilProxy = (app: FastifyInstance) => { const config = getConfig(); + + if (!config.mithril.enabled) { + return; + } + + console.log(`Mithril proxy enabled. Aggregator: ${config.mithril.aggregator}.`); + const snapshotCDN = config.mithril.snapshotCDN; app.register(fastifyHttpProxy, { @@ -43,23 +50,22 @@ export const registerMithrilProxy = (app: FastifyInstance) => { const isErrorResponse = reply.statusCode >= 400; if (isErrorResponse) { - // When replying with a body of a different length it is necessary to remove the content-length header. - reply.removeHeader('content-length'); - // error response returned from the proxy can originate from: - // 1) Mithril Aggregator, 2) varnish, 3) nginx, 4) whatever - // Mithril Aggregator returns only error status codes without body - if (reply.statusCode === 404) { - return handle404(reply as FastifyReply); - } else if (reply.statusCode === 412) { - return reply.code(412).send({ - error: 'Api Version mismatch', - message: - 'Api Version mismatch. Please check https://docs.blockfrost.io/#section/Mithril', - status_code: 412, - }); + // 1) Mithril Aggregator or 2) some middleware in between (nginx/varnish/etc) + // Mithril Aggregator returns 404, 412 error status codes without body + // 500 comes with label and message props + const isMithrilError = reply.hasHeader('mithril-api-version'); + + if (isMithrilError) { + // Set custom header for errors that originate from Mithril + reply.header('X-Mithril-Error', '1'); + return reply.send(response); } else { + // Unexpected error const errorBody = await convertStreamToString(response); + // When replying with a body of a different length it is necessary to remove the content-length header. + + reply.removeHeader('content-length'); return handle500(reply as FastifyReply, errorBody, request as FastifyRequest); } diff --git a/test/unit/tests/proxies/mithril.test.ts b/test/unit/tests/proxies/mithril.test.ts index 291dae92..12096dfa 100644 --- a/test/unit/tests/proxies/mithril.test.ts +++ b/test/unit/tests/proxies/mithril.test.ts @@ -348,7 +348,7 @@ describe('mithril proxy text', () => { test('error handling - mithril aggregator error (404) should be forwarded', async () => { const app = buildFastify(); - nock(mithrilAggregatorURL).get('/').reply(404); + nock(mithrilAggregatorURL).get('/').reply(404, undefined, { 'mithril-api-version': '0.1.21' }); const response = await app.inject({ method: 'GET', @@ -356,19 +356,13 @@ describe('mithril proxy text', () => { }); expect(response.statusCode).toBe(404); - expect(response.body).toBe( - JSON.stringify({ - error: 'Not Found', - message: 'The requested component has not been found.', - status_code: 404, - }), - ); + expect(response.body).toBe(''); }); test('error handling - mithril aggregator error (412) should be forwarded', async () => { const app = buildFastify(); - nock(mithrilAggregatorURL).get('/').reply(412); + nock(mithrilAggregatorURL).get('/').reply(412, undefined, { 'mithril-api-version': '0.1.21' }); const response = await app.inject({ method: 'GET', @@ -376,31 +370,21 @@ describe('mithril proxy text', () => { }); expect(response.statusCode).toBe(412); - expect(response.body).toBe( - JSON.stringify({ - error: 'Api Version mismatch', - message: 'Api Version mismatch. Please check https://docs.blockfrost.io/#section/Mithril', - status_code: 412, - }), - ); + expect(response.body).toBe(''); }); - test('error handling - unknown mithril aggregator error (400) returns as 500', async () => { + test('error handling - unknown mithril aggregator error (400) forwarded', async () => { const app = buildFastify(); - nock(mithrilAggregatorURL).get('/').reply(400, 'unexpected body'); + nock(mithrilAggregatorURL) + .get('/') + .reply(400, 'unexpected body', { 'mithril-api-version': '0.1.21' }); const response = await app.inject({ method: 'GET', url: '/mithril/', }); - expect(response.statusCode).toBe(500); - expect(response.body).toBe( - JSON.stringify({ - error: 'Internal Server Error', - message: 'An unexpected response was received from the backend.', - status_code: 500, - }), - ); + expect(response.statusCode).toBe(400); + expect(response.body).toBe('unexpected body'); }); });