Skip to content

Commit 54b3e4f

Browse files
Merge pull request #1587 from SteadEXE/master
fix(fastify): serve index file when it exists
2 parents 117fe43 + cad5d89 commit 54b3e4f

File tree

2 files changed

+184
-82
lines changed

2 files changed

+184
-82
lines changed

lib/loaders/fastify.loader.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,26 @@ export class FastifyLoader extends AbstractLoader {
4141
}
4242

4343
const renderFn = (req: any, res: any) => {
44-
fs.stat(indexFilePath, (err) => {
44+
if (!options.serveStaticOptions?.fallthrough) {
45+
const error = new NotFoundException();
46+
res.status(error.getStatus()).send(error.getResponse());
47+
return;
48+
}
49+
50+
fs.stat(indexFilePath, (err, stat) => {
4551
if (err) {
46-
const stream = fs.createReadStream(indexFilePath);
47-
if (options.serveStaticOptions?.setHeaders) {
48-
const stat = fs.statSync(indexFilePath);
49-
options.serveStaticOptions.setHeaders(res, indexFilePath, stat);
50-
}
51-
res.type('text/html').send(stream);
52-
} else {
5352
const error = new NotFoundException();
5453
res.status(error.getStatus()).send(error.getResponse());
54+
return;
5555
}
56+
57+
const stream = fs.createReadStream(indexFilePath);
58+
59+
if (options.serveStaticOptions?.setHeaders) {
60+
options.serveStaticOptions.setHeaders(res, indexFilePath, stat);
61+
}
62+
63+
res.type('text/html').send(stream);
5664
});
5765
};
5866

tests/e2e/fastify-adapter.e2e-spec.ts

Lines changed: 168 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,95 +5,189 @@ import {
55
} from '@nestjs/platform-fastify';
66
import { AppModule } from '../src/app.module';
77
import { NoopLogger } from '../utils/noop-logger';
8+
import request from 'supertest';
89

910
describe('Fastify adapter', () => {
1011
let app: NestFastifyApplication;
1112

12-
beforeAll(async () => {
13-
app = await NestFactory.create(
14-
AppModule.withDefaults(),
15-
new FastifyAdapter(),
16-
{
17-
logger: new NoopLogger()
18-
}
19-
);
20-
app.setGlobalPrefix('api');
21-
22-
await app.init();
23-
await app.getHttpAdapter().getInstance().ready();
24-
});
13+
describe('when "fallthrough" option is set to "true"', () => {
14+
beforeAll(async () => {
15+
app = await NestFactory.create(
16+
AppModule.withFallthrough(),
17+
new FastifyAdapter(),
18+
{
19+
logger: new NoopLogger()
20+
}
21+
);
22+
app.setGlobalPrefix('api');
2523

26-
describe('GET /api', () => {
27-
it('should return "Hello, world!"', async () => {
28-
return app
29-
.inject({
30-
method: 'GET',
31-
url: '/api'
32-
})
33-
.then((result) => {
34-
expect(result.statusCode).toEqual(200);
35-
expect(result.payload).toEqual('Hello, world!');
36-
});
24+
await app.init();
25+
await app.getHttpAdapter().getInstance().ready();
3726
});
38-
});
3927

40-
describe('GET /', () => {
41-
it('should return HTML file', async () => {
42-
return app
43-
.inject({
44-
method: 'GET',
45-
url: '/'
46-
})
47-
.then((result) => {
48-
expect(result.statusCode).toEqual(200);
49-
expect(result.headers['content-type']).toMatch(/html/);
50-
expect(result.payload).toContain('Static website');
51-
});
28+
describe('GET /api', () => {
29+
it('should return "Hello, world!"', async () => {
30+
return app
31+
.inject({
32+
method: 'GET',
33+
url: '/api'
34+
})
35+
.then((result) => {
36+
expect(result.statusCode).toEqual(200);
37+
expect(result.payload).toEqual('Hello, world!');
38+
});
39+
});
5240
});
53-
});
5441

55-
describe('GET /index.html', () => {
56-
it('should return index page', async () => {
57-
return app
58-
.inject({
59-
method: 'GET',
60-
url: '/index.html'
61-
})
62-
.then((result) => {
63-
expect(result.statusCode).toEqual(200);
64-
expect(result.payload).toContain('Static website');
65-
});
42+
describe('GET /', () => {
43+
it('should return HTML file', async () => {
44+
return app
45+
.inject({
46+
method: 'GET',
47+
url: '/'
48+
})
49+
.then((result) => {
50+
expect(result.statusCode).toEqual(200);
51+
expect(result.headers['content-type']).toMatch(/html/);
52+
expect(result.payload).toContain('Static website');
53+
});
54+
});
6655
});
67-
});
6856

69-
describe('GET /logo.svg', () => {
70-
it('should return logo', async () => {
71-
return app
72-
.inject({
73-
method: 'GET',
74-
url: '/logo.svg'
75-
})
76-
.then((result) => {
77-
expect(result.statusCode).toEqual(200);
78-
expect(result.headers['content-type']).toMatch(/image/);
79-
});
57+
describe('GET /index.html', () => {
58+
it('should return index page', async () => {
59+
return app
60+
.inject({
61+
method: 'GET',
62+
url: '/index.html'
63+
})
64+
.then((result) => {
65+
expect(result.statusCode).toEqual(200);
66+
expect(result.payload).toContain('Static website');
67+
});
68+
});
69+
});
70+
71+
describe('GET /logo.svg', () => {
72+
it('should return logo', async () => {
73+
return app
74+
.inject({
75+
method: 'GET',
76+
url: '/logo.svg'
77+
})
78+
.then((result) => {
79+
expect(result.statusCode).toEqual(200);
80+
expect(result.headers['content-type']).toMatch(/image/);
81+
});
82+
});
83+
});
84+
85+
describe('when trying to get a non-existing file', () => {
86+
it('should returns index page', async () => {
87+
return app
88+
.inject({
89+
method: 'GET',
90+
url: '/404'
91+
})
92+
.then((result) => {
93+
expect(result.statusCode).toEqual(200);
94+
expect(result.payload).toContain('Static website');
95+
});
96+
});
8097
});
81-
});
8298

83-
describe('when trying to get a non-existing file', () => {
84-
it('should return 404', async () => {
85-
return app
86-
.inject({
87-
method: 'GET',
88-
url: '/404'
89-
})
90-
.then((result) => {
91-
expect(result.statusCode).toEqual(404);
92-
});
99+
afterAll(async () => {
100+
await app.close();
93101
});
94102
});
95103

96-
afterAll(async () => {
97-
await app.close();
104+
describe('when "fallthrough" option is set to "false"', () => {
105+
beforeAll(async () => {
106+
app = await NestFactory.create(
107+
AppModule.withoutFallthrough(),
108+
new FastifyAdapter(),
109+
{
110+
logger: new NoopLogger()
111+
}
112+
);
113+
app.setGlobalPrefix('api');
114+
115+
await app.init();
116+
await app.getHttpAdapter().getInstance().ready();
117+
});
118+
119+
describe('GET /api', () => {
120+
it('should return "Hello, world!"', async () => {
121+
return app
122+
.inject({
123+
method: 'GET',
124+
url: '/api'
125+
})
126+
.then((result) => {
127+
expect(result.statusCode).toEqual(200);
128+
expect(result.payload).toEqual('Hello, world!');
129+
});
130+
});
131+
});
132+
133+
describe('GET /', () => {
134+
it('should return HTML file', async () => {
135+
return app
136+
.inject({
137+
method: 'GET',
138+
url: '/'
139+
})
140+
.then((result) => {
141+
expect(result.statusCode).toEqual(200);
142+
expect(result.headers['content-type']).toMatch(/html/);
143+
expect(result.payload).toContain('Static website');
144+
});
145+
});
146+
});
147+
148+
describe('GET /index.html', () => {
149+
it('should return index page', async () => {
150+
return app
151+
.inject({
152+
method: 'GET',
153+
url: '/index.html'
154+
})
155+
.then((result) => {
156+
expect(result.statusCode).toEqual(200);
157+
expect(result.payload).toContain('Static website');
158+
});
159+
});
160+
});
161+
162+
describe('GET /logo.svg', () => {
163+
it('should return logo', async () => {
164+
return app
165+
.inject({
166+
method: 'GET',
167+
url: '/logo.svg'
168+
})
169+
.then((result) => {
170+
expect(result.statusCode).toEqual(200);
171+
expect(result.headers['content-type']).toMatch(/image/);
172+
});
173+
});
174+
});
175+
176+
describe('when trying to get a non-existing file', () => {
177+
it('should return 404', async () => {
178+
return app
179+
.inject({
180+
method: 'GET',
181+
url: '/404'
182+
})
183+
.then((result) => {
184+
expect(result.statusCode).toEqual(404);
185+
});
186+
});
187+
});
188+
189+
afterAll(async () => {
190+
await app.close();
191+
});
98192
});
99193
});

0 commit comments

Comments
 (0)