-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add API request validation #3
Conversation
@@ -1,12 +1,8 @@ | |||
import { db } from "../../db" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When trying to use absolute paths. Deployed code was failing with unable to find module
error.
Hence backend uses relative paths now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect it's this issue serverless/serverless-plugin-typescript#180
@@ -89,7 +90,7 @@ describe('Test entity API', () => { | |||
entityToUpdate = await repo.createQueryBuilder("game").getOneOrFail() | |||
|
|||
expect(entityToUpdate.name).not.toEqual(updatedEntity.name) | |||
await updateById({ pathParameters: { gameId: entityToUpdate.id }, body: JSON.stringify(updatedEntity) } as unknown as APIGatewayProxyEventV2) as Game | |||
await updateByIdHandler({ pathParameters: { gameId: entityToUpdate.id }, body: JSON.stringify(updatedEntity) } as unknown as APIGatewayProxyEventV2) as Game |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type casting with as
is kinda ugly here, but had to use it because of type signatures for lambdas looking like this:
(event: APIGatewayProxyEventV2): Promise<APIGatewayProxyResultV2<Game>>
When testing we don't need and don't have things featured on APIGatewayProxyEventV2
and APIGatewayProxyResultV2
interfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can updateByIdHandler
have a return type of Game?
Should we have a helper that builds a fake APIGatewayProxyEventV2 object so we don't need to type cast?
@@ -1,44 +1,39 @@ | |||
listGames: | |||
handler: src/api/game/crud.list | |||
handler: src/api/game/crud.listHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case you wonder what those Game
models and API endpoints are, they're just examples the project is gonna get generated with.
I think it's gonna turn out helpful for whoever's using our template.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice progress! Let's try to think about how to keep things simple like this, without requiring too much boilerplate or repeating ourselves for CRUD. It's a tricky balance.
Are there no existing libraries or frameworks we can be leveraging here?
If not, this would be a great project to try to promote as its own framework
@@ -89,7 +90,7 @@ describe('Test entity API', () => { | |||
entityToUpdate = await repo.createQueryBuilder("game").getOneOrFail() | |||
|
|||
expect(entityToUpdate.name).not.toEqual(updatedEntity.name) | |||
await updateById({ pathParameters: { gameId: entityToUpdate.id }, body: JSON.stringify(updatedEntity) } as unknown as APIGatewayProxyEventV2) as Game | |||
await updateByIdHandler({ pathParameters: { gameId: entityToUpdate.id }, body: JSON.stringify(updatedEntity) } as unknown as APIGatewayProxyEventV2) as Game |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can updateByIdHandler
have a return type of Game?
Should we have a helper that builds a fake APIGatewayProxyEventV2 object so we don't need to type cast?
|
||
return { | ||
items: games, | ||
paginationData: getPaginationData(totalCount, pagesData), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like putting pagination metadata in headers
Don't name identifiers with "data"
|
||
const apiName = process.env.REACT_APP_USE_APP_WITHOUT_AUTH ? undefined : process.env.REACT_APP_API_NAME // name of the API Gateway API | ||
|
||
const myInit = { | ||
// OPTIONAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit confused what this is
generators/model/templates/domain.ts
Outdated
export const create = async (event: { body: <%= modelSchemaName %> }): Promise < APIGatewayProxyResultV2 <<%= capitalizedModelName %>>> => { | ||
|
||
const conn = await db.getConnection() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think we need all these newlines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will add ESLint and Prettier this week, which will hopefully handle spacing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job!
Main changes
Due to quite a few changes to Yeoman generators in this PR it's a bit lengthy.
Main concepts regarding request validation are represented primarily in:
generators/app/templates/packages/backend/src/domain/game.ts
generators/app/templates/packages/backend/src/api/game/crud.ts
generators/app/templates/packages/backend/src/util/serialization.ts
What does this PR do?
Request bodies will now be validated using class-validator and lambda-middleware class-validator
We can't add validation as decorators. Instead we need to take an existing function and generate the Lambda handler from it.
My idea is to have all the functions for API in
domain
and the actual APIviews
have only exports of modified functions.Here's how an API view would look like with this setup:
The PR also includes related changes to Yeoman generator and Jest tests.