diff --git a/src/api/init.ts b/src/api/init.ts index b9b53b4607..905b1d91ed 100644 --- a/src/api/init.ts +++ b/src/api/init.ts @@ -58,6 +58,9 @@ export interface ApiServer { forceKill: () => Promise; } +/** API version as given by .git-info */ +export const API_VERSION: { branch?: string; commit?: string; tag?: string } = {}; + export async function startApiServer(opts: { datastore: PgStore; writeDatastore?: PgWriteStore; @@ -70,6 +73,15 @@ export async function startApiServer(opts: { }): Promise { const { datastore, writeDatastore, chainId, serverHost, serverPort, httpLogLevel } = opts; + try { + const [branch, commit, tag] = fs.readFileSync('.git-info', 'utf-8').split('\n'); + API_VERSION.branch = branch; + API_VERSION.commit = commit; + API_VERSION.tag = tag; + } catch (error) { + logger.error(`Unable to read API version from .git-info`, error); + } + const app = express(); const apiHost = serverHost ?? process.env['STACKS_BLOCKCHAIN_API_HOST']; const apiPort = serverPort ?? parseInt(process.env['STACKS_BLOCKCHAIN_API_PORT'] ?? ''); @@ -128,6 +140,15 @@ export async function startApiServer(opts: { }); app.use(promMiddleware); } + // Add API version to header + app.use((_, res, next) => { + res.setHeader( + 'X-API-Version', + `${API_VERSION.tag} (${API_VERSION.branch}:${API_VERSION.commit})` + ); + res.append('Access-Control-Expose-Headers', 'X-API-Version'); + next(); + }); // Setup request logging app.use( expressWinston.logger({ diff --git a/src/api/routes/status.ts b/src/api/routes/status.ts index c99aae463d..f4ae1af460 100644 --- a/src/api/routes/status.ts +++ b/src/api/routes/status.ts @@ -4,15 +4,15 @@ import { ServerStatusResponse } from '@stacks/stacks-blockchain-api-types'; import { logger } from '../../helpers'; import { getETagCacheHandler, setETagCacheHeaders } from '../controllers/cache-controller'; import { PgStore } from '../../datastore/pg-store'; +import { API_VERSION } from '../init'; export function createStatusRouter(db: PgStore): express.Router { const router = express.Router(); const cacheHandler = getETagCacheHandler(db); const statusHandler = async (_: Request, res: any) => { try { - const [branch, commit, tag] = fs.readFileSync('.git-info', 'utf-8').split('\n'); const response: ServerStatusResponse = { - server_version: `stacks-blockchain-api ${tag} (${branch}:${commit})`, + server_version: `stacks-blockchain-api ${API_VERSION.tag} (${API_VERSION.branch}:${API_VERSION.commit})`, status: 'ready', }; const chainTip = await db.getUnanchoredChainTip(); @@ -28,7 +28,6 @@ export function createStatusRouter(db: PgStore): express.Router { setETagCacheHeaders(res); res.json(response); } catch (error) { - logger.error(`Unable to read git info`, error); const response: ServerStatusResponse = { status: 'ready', };