Skip to content

Commit

Permalink
fix: handle invalid request path properly in openapi handler (zenstac…
Browse files Browse the repository at this point in the history
  • Loading branch information
ymc9 authored Mar 29, 2023
2 parents 920b13e + bda4a4f commit 955e657
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 21 deletions.
14 changes: 5 additions & 9 deletions packages/server/src/openapi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
} from '@zenstackhq/runtime';
import type { ModelZodSchema } from '@zenstackhq/runtime/zod';
import { capitalCase } from 'change-case';
import invariant from 'tiny-invariant';
import { fromZodError } from 'zod-validation-error';
import { stripAuxFields } from './utils';

Expand Down Expand Up @@ -96,18 +95,15 @@ export async function handleRequest({
logger,
zodSchemas,
}: RequestContext): Promise<Response> {
const parts = path.split('/');
if (parts.length < 2) {
return { status: 400, body: { error: 'invalid request path' } };
}

method = method.toUpperCase();
const parts = path.split('/').filter((p) => !!p);
const op = parts.pop();
const model = parts.pop();

invariant(op);
invariant(model);
if (parts.length !== 0 || !op || !model) {
return { status: 400, body: { message: 'invalid request path' } };
}

method = method.toUpperCase();
const dbOp = op as keyof DbOperations;
let args: unknown;
let resCode = 200;
Expand Down
17 changes: 17 additions & 0 deletions packages/server/tests/express-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,21 @@ describe('Express adapter tests', () => {
expect(r.status).toBe(200);
expect(r.body.count).toBe(1);
});

it('invalid path or args', async () => {
const { prisma, zodSchemas } = await loadSchema(schema);

const app = express();
app.use(bodyParser.json());
app.use('/api', ZenStackMiddleware({ getPrisma: () => prisma, zodSchemas }));

let r = await request(app).get('/api/post/');
expect(r.status).toBe(400);

r = await request(app).get('/api/post/findMany/abc');
expect(r.status).toBe(400);

r = await request(app).get('/api/post/findMany?q=abc');
expect(r.status).toBe(400);
});
});
29 changes: 29 additions & 0 deletions packages/server/tests/fastify-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,33 @@ describe('Fastify adapter tests', () => {
expect(r.statusCode).toBe(200);
expect(r.json().count).toBe(1);
});

it('invalid path or args', async () => {
const { prisma, zodSchemas } = await loadSchema(schema);

const app = fastify();
app.register(ZenStackFastifyPlugin, {
prefix: '/api',
getPrisma: () => prisma,
zodSchemas,
});

let r = await app.inject({
method: 'GET',
url: '/api/post/',
});
expect(r.statusCode).toBe(400);

r = await app.inject({
method: 'GET',
url: '/api/post/findMany/abc',
});
expect(r.statusCode).toBe(400);

r = await app.inject({
method: 'GET',
url: '/api/post/findMany?q=abc',
});
expect(r.statusCode).toBe(400);
});
});
62 changes: 50 additions & 12 deletions packages/server/tests/open-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('OpenAPI server tests', () => {

let r = await handleRequest({
method: 'get',
path: '/api/post/findMany',
path: '/post/findMany',
prisma,
zodSchemas,
});
Expand All @@ -20,7 +20,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'post',
path: '/api/user/create',
path: '/user/create',
query: {},
requestBody: {
include: { posts: true },
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'get',
path: '/api/post/findMany',
path: '/post/findMany',
prisma,
zodSchemas,
});
Expand All @@ -65,7 +65,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'get',
path: '/api/post/findMany',
path: '/post/findMany',
query: { q: JSON.stringify({ where: { viewCount: { gt: 1 } } }) },
prisma,
zodSchemas,
Expand All @@ -75,7 +75,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'put',
path: '/api/user/update',
path: '/user/update',
requestBody: { where: { id: 'user1' }, data: { email: 'user1@def.com' } },
prisma,
zodSchemas,
Expand All @@ -85,7 +85,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'get',
path: '/api/post/count',
path: '/post/count',
query: { q: JSON.stringify({ where: { viewCount: { gt: 1 } } }) },
prisma,
zodSchemas,
Expand All @@ -95,7 +95,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'get',
path: '/api/post/aggregate',
path: '/post/aggregate',
query: { q: JSON.stringify({ _sum: { viewCount: true } }) },
prisma,
zodSchemas,
Expand All @@ -105,7 +105,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'get',
path: '/api/post/groupBy',
path: '/post/groupBy',
query: { q: JSON.stringify({ by: ['published'], _sum: { viewCount: true } }) },
prisma,
zodSchemas,
Expand All @@ -120,7 +120,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'delete',
path: '/api/user/deleteMany',
path: '/user/deleteMany',
query: { q: JSON.stringify({ where: { id: 'user1' } }) },
prisma,
zodSchemas,
Expand All @@ -135,14 +135,14 @@ describe('OpenAPI server tests', () => {
// without validation
let r = await handleRequest({
method: 'get',
path: '/api/post/findUnique',
path: '/post/findUnique',
prisma,
});
expect(r.status).toBe(400);

r = await handleRequest({
method: 'get',
path: '/api/post/findUnique',
path: '/post/findUnique',
prisma,
zodSchemas,
});
Expand All @@ -152,7 +152,7 @@ describe('OpenAPI server tests', () => {

r = await handleRequest({
method: 'post',
path: '/api/post/create',
path: '/post/create',
requestBody: { data: {} },
prisma,
zodSchemas,
Expand All @@ -161,4 +161,42 @@ describe('OpenAPI server tests', () => {
expect((r.body as any).message).toContain('Validation error');
expect((r.body as any).message).toContain('data.title');
});

it('invalid path or args', async () => {
const { prisma } = await loadSchema(schema);

let r = await handleRequest({
method: 'get',
path: '/post/',
prisma,
});
expect(r.status).toBe(400);
expect((r.body as any).message).toContain('invalid request path');

r = await handleRequest({
method: 'get',
path: '/post/findMany/abc',
prisma,
});
expect(r.status).toBe(400);
expect((r.body as any).message).toContain('invalid request path');

r = await handleRequest({
method: 'get',
path: '/post/findUnique',
query: { q: 'abc' },
prisma,
});
expect(r.status).toBe(400);
expect((r.body as any).message).toContain('query param must contain valid JSON');

r = await handleRequest({
method: 'delete',
path: '/post/deleteMany',
query: { q: 'abc' },
prisma,
});
expect(r.status).toBe(400);
expect((r.body as any).message).toContain('query param must contain valid JSON');
});
});

0 comments on commit 955e657

Please sign in to comment.