Skip to content

Commit 036cf64

Browse files
authored
feat: throw error if /api routes defined (#142)
1 parent 56a380b commit 036cf64

File tree

4 files changed

+79
-3
lines changed

4 files changed

+79
-3
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,25 @@ export default {
172172
};
173173
```
174174

175+
### allowReservedSwaRoutes
176+
177+
In production, Azure SWA will route any requests to `/api` or `/api/*` to the SWA [API backend](https://learn.microsoft.com/en-us/azure/static-web-apps/apis-overview). If you also define SvelteKit routes beginning with `/api`, those requests will work in dev, but return a 404 in production since the request will be routed to the SWA API. Because of this, the adapter will throw an error at build time if it detects any routes beginning with `/api`.
178+
179+
If you want to disable this check, you can set `allowReservedSwaRoutes` to true. However, this will not start routing `/api` requests to your SvelteKit app. SWA does not allow configuring the `/api` route.
180+
181+
```js
182+
import azure from 'svelte-adapter-azure-swa';
183+
184+
export default {
185+
kit: {
186+
...
187+
adapter: azure({
188+
allowReservedSwaRoutes: true
189+
})
190+
}
191+
};
192+
```
193+
175194
### esbuildOptions
176195

177196
An object containing additional [esbuild options](https://esbuild.github.io/api/#build-api). Currently only supports [external](https://esbuild.github.io/api/#external). If you require additional options to be exposed, plese [open an issue](https://github.com/geoffrich/svelte-adapter-azure-swa/issues).

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export type Options = {
1111
esbuildOptions?: Pick<esbuild.BuildOptions, 'external'>;
1212
apiDir?: string;
1313
staticDir?: string;
14+
allowReservedSwaRoutes?: boolean;
1415
};
1516

1617
export default function plugin(options?: Options): Adapter;

index.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ export default function ({
4949
customStaticWebAppConfig = {},
5050
esbuildOptions = {},
5151
apiDir: customApiDir = undefined,
52-
staticDir: customStaticDir = undefined
52+
staticDir: customStaticDir = undefined,
53+
allowReservedSwaRoutes = false
5354
} = {}) {
5455
return {
5556
name: 'adapter-azure-swa',
@@ -62,6 +63,24 @@ export default function ({
6263
Please see the PR for migration instructions: https://github.com/geoffrich/svelte-adapter-azure-swa/pull/92`
6364
);
6465
}
66+
67+
const conflictingRoutes =
68+
builder.routes?.map((route) => route.id).filter((routeId) => routeId.startsWith('/api')) ??
69+
[];
70+
if (!allowReservedSwaRoutes && conflictingRoutes.length > 0) {
71+
builder.log.error(
72+
`Error: the following routes conflict with Azure SWA's reserved /api route: ${conflictingRoutes.join(
73+
', '
74+
)}. Requests to these routes in production will return 404 instead of hitting your SvelteKit app.
75+
76+
To resolve this error, move the conflicting routes so they do not start with /api. For example, move /api/blog to /blog.
77+
If you want to suppress this error, set allowReservedSwaRoutes to true in your adapter options.
78+
`
79+
);
80+
81+
throw new Error('Conflicting routes detected. Please rename the routes listed above.');
82+
}
83+
6584
const swaConfig = generateConfig(customStaticWebAppConfig, builder.config.kit.appDir);
6685

6786
const tmp = builder.getBuildDirectory('azure-tmp');

test/index.test.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,34 @@ describe('adapt', () => {
123123
)
124124
);
125125
});
126+
127+
test.each(['/api', '/api/foo'])('throws error when the app defines %s route', async (routeId) => {
128+
const adapter = azureAdapter();
129+
const builder = getMockBuilder();
130+
builder.routes.push({
131+
id: routeId
132+
});
133+
await expect(adapter.adapt(builder)).rejects.toThrowError(
134+
'Conflicting routes detected. Please rename the routes listed above.'
135+
);
136+
});
137+
138+
test('does not throw error for /api route if allowReservedSwaRoutes is defined', async () => {
139+
const adapter = azureAdapter({ allowReservedSwaRoutes: true });
140+
const builder = getMockBuilder();
141+
builder.routes.push({
142+
id: '/api'
143+
});
144+
await expect(adapter.adapt(builder)).resolves.not.toThrow();
145+
});
146+
147+
test('handles null routes', async () => {
148+
// builder.routes was added in 1.5 with route-level config
149+
const adapter = azureAdapter();
150+
const builder = getMockBuilder();
151+
builder.routes = null;
152+
await expect(adapter.adapt(builder)).resolves.not.toThrow();
153+
});
126154
});
127155

128156
/** @returns {import('@sveltejs/kit').Builder} */
@@ -135,7 +163,8 @@ function getMockBuilder() {
135163
},
136164
log: {
137165
minor: vi.fn(),
138-
warn: vi.fn()
166+
warn: vi.fn(),
167+
error: vi.fn()
139168
},
140169
prerendered: {
141170
paths: ['/']
@@ -146,6 +175,14 @@ function getMockBuilder() {
146175
getServerDirectory: vi.fn(() => 'server'),
147176
rimraf: vi.fn(),
148177
writeClient: vi.fn(),
149-
writePrerendered: vi.fn()
178+
writePrerendered: vi.fn(),
179+
routes: [
180+
{
181+
id: '/'
182+
},
183+
{
184+
id: '/about'
185+
}
186+
]
150187
};
151188
}

0 commit comments

Comments
 (0)