diff --git a/.changeset/funny-lobsters-promise.md b/.changeset/funny-lobsters-promise.md new file mode 100644 index 000000000000..6b77e442ccbe --- /dev/null +++ b/.changeset/funny-lobsters-promise.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes an issue where configuring trailingSlash had no effect on API routes. diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index f87d5fcd2511..247a01ad1896 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -328,7 +328,7 @@ export function createRouteManifest( } else { components.push(item.file); const component = item.file; - const trailingSlash = item.isPage ? settings.config.trailingSlash : 'never'; + const { trailingSlash } = settings.config; const pattern = getPattern(segments, settings.config, trailingSlash); const generate = getRouteGenerator(segments, trailingSlash); const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) diff --git a/packages/astro/test/units/routing/trailing-slash.test.js b/packages/astro/test/units/routing/trailing-slash.test.js new file mode 100644 index 000000000000..c707c7215a5d --- /dev/null +++ b/packages/astro/test/units/routing/trailing-slash.test.js @@ -0,0 +1,59 @@ +import { + createBasicSettings, + createFs, + createRequestAndResponse, + defaultLogger, +} from '../test-utils.js'; +import { fileURLToPath } from 'node:url'; +import { expect } from 'chai'; +import { createContainer } from '../../../dist/core/dev/container.js'; +import testAdapter from '../../test-adapter.js'; + +const root = new URL('../../fixtures/api-routes/', import.meta.url); +const fileSystem = { + '/src/pages/api.ts': `export const GET = () => Response.json({ success: true })`, +}; + +describe('trailingSlash', () => { + let container; + let settings; + + before(async () => { + const fs = createFs(fileSystem, root); + settings = await createBasicSettings({ + root: fileURLToPath(root), + trailingSlash: 'always', + output: 'server', + adapter: testAdapter(), + }); + container = await createContainer({ + fs, + settings, + logger: defaultLogger, + }); + }); + + after(async () => { + await container.close(); + }); + + it('should match the API route when request has a trailing slash', async () => { + const { req, res, text } = createRequestAndResponse({ + method: 'GET', + url: '/api/', + }); + container.handle(req, res); + const json = await text(); + expect(json).to.equal('{"success":true}'); + }); + + it('should NOT match the API route when request lacks a trailing slash', async () => { + const { req, res, text } = createRequestAndResponse({ + method: 'GET', + url: '/api', + }); + container.handle(req, res); + expect(await text()).to.equal(''); + expect(res.statusCode).to.equal(404); + }); +});