Skip to content

Commit ddd2cdf

Browse files
authored
feat(public-api): add endpoint to list all tags (#3571)
1 parent 80072bf commit ddd2cdf

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

__tests__/routes/public/tags.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import request from 'supertest';
2+
import { setupPublicApiTests, createTokenForUser } from './helpers';
3+
import { Keyword } from '../../../src/entity/Keyword';
4+
5+
const state = setupPublicApiTests();
6+
7+
describe('GET /public/v1/tags', () => {
8+
beforeEach(async () => {
9+
await state.con.getRepository(Keyword).save([
10+
{ value: 'eng688tagalpha', status: 'allow' },
11+
{ value: 'eng688tagbeta', status: 'allow' },
12+
]);
13+
});
14+
15+
it('should return all tags for authenticated user', async () => {
16+
const token = await createTokenForUser(state.con, '5');
17+
18+
const { body } = await request(state.app.server)
19+
.get('/public/v1/tags')
20+
.set('Authorization', `Bearer ${token}`)
21+
.expect(200);
22+
23+
expect(Array.isArray(body.data)).toBe(true);
24+
expect(body.data).toEqual(
25+
expect.arrayContaining([
26+
{ name: 'eng688tagalpha' },
27+
{ name: 'eng688tagbeta' },
28+
]),
29+
);
30+
});
31+
32+
it('should return 401 without auth header', async () => {
33+
await request(state.app.server).get('/public/v1/tags').expect(401);
34+
});
35+
36+
it('should return data array without pagination', async () => {
37+
const token = await createTokenForUser(state.con, '5');
38+
39+
const { body } = await request(state.app.server)
40+
.get('/public/v1/tags')
41+
.set('Authorization', `Bearer ${token}`)
42+
.expect(200);
43+
44+
expect(body).toMatchObject({
45+
data: expect.any(Array),
46+
});
47+
expect(body.pagination).toBeUndefined();
48+
});
49+
});

src/routes/public/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import notificationsRoutes from './notifications';
1212
import profileRoutes from './profile';
1313
import stackRoutes from './stack';
1414
import experiencesRoutes from './experiences';
15+
import tagsRoutes from './tags';
1516
import { commonSchemas } from './schemas';
1617
import { PUBLIC_API_PREFIX } from '../../common/constants';
1718

@@ -192,4 +193,5 @@ export default async function (
192193
await fastify.register(profileRoutes, { prefix: '/profile' });
193194
await fastify.register(stackRoutes, { prefix: '/profile/stack' });
194195
await fastify.register(experiencesRoutes, { prefix: '/profile/experiences' });
196+
await fastify.register(tagsRoutes, { prefix: '/tags' });
195197
}

src/routes/public/tags.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { FastifyInstance } from 'fastify';
2+
import { executeGraphql } from './graphqlExecutor';
3+
import { ensureDbConnection } from './common';
4+
5+
const TAGS_QUERY = `
6+
query PublicApiTags {
7+
tags {
8+
value
9+
}
10+
}
11+
`;
12+
13+
type TagsResponse = {
14+
tags: { value: string }[];
15+
};
16+
17+
export default async function (fastify: FastifyInstance): Promise<void> {
18+
fastify.get(
19+
'/',
20+
{
21+
schema: {
22+
description: 'Get all tags',
23+
tags: ['tags'],
24+
response: {
25+
200: {
26+
type: 'object',
27+
properties: {
28+
data: { type: 'array', items: { $ref: 'Tag#' } },
29+
},
30+
},
31+
401: { $ref: 'Error#' },
32+
429: { $ref: 'RateLimitError#' },
33+
},
34+
},
35+
},
36+
async (request, reply) => {
37+
const con = ensureDbConnection(fastify.con);
38+
39+
return executeGraphql(
40+
con,
41+
{
42+
query: TAGS_QUERY,
43+
variables: {},
44+
},
45+
(json) => ({
46+
data: (json as TagsResponse).tags.map(({ value }) => ({
47+
name: value,
48+
})),
49+
}),
50+
request,
51+
reply,
52+
);
53+
},
54+
);
55+
}

0 commit comments

Comments
 (0)