This commit is contained in:
pfych 2024-10-12 14:08:09 +11:00
commit 0029086b3f
148 changed files with 19047 additions and 0 deletions

View file

@ -0,0 +1,102 @@
import { Response } from 'express';
import { {{ nameCamel }}Mapper } from './{{ nameKebab }}';
import { isAdmin } from '../../middleware/is-admin';
import { RequestContext } from '../../util/request-context.type';
import { {{ nameFirst }} } from '@baseline/types/{{ nameKebab }}';
import { getErrorMessage } from '../../util/error-message';
import createApp from '../../util/express-app';
import createAuthenticatedHandler from '../../util/create-authenticated-handler';
import { {{ nameCamel }}Service } from './{{ nameKebab }}.service';
const app = createApp();
// app.use(isAdmin); // All private endpoints require the user to be an admin
export const handler = createAuthenticatedHandler(app);
app.post('/{{ nameKebab }}', [
isAdmin,
async (req: RequestContext, res: Response) => {
try {
const { {{ apiCreateFields }} } = req.body as {{ nameFirst }};
const {{ nameCamel }}Data: Partial<{{ nameFirst }}> = {
{{ apiCreateFields }},
};
const {{ nameCamel }} = await {{ nameCamel }}Service.create({{ nameCamel }}Data);
res.json({{ nameCamel }}Mapper({{ nameCamel }}));
} catch (error) {
const message = getErrorMessage(error);
console.error(`Failed to create {{ nameLower }} ${message}`);
res.status(400).json({ error: 'Failed to create {{ nameLower }}' });
}
},
]);
app.patch('/{{ nameKebab }}', [
isAdmin,
async (req: RequestContext, res: Response) => {
try {
const { {{ apiUpdateFields }} } = req.body as {{ nameFirst }};
const {{ nameCamel }}Data: Partial<{{ nameFirst }}> = {
{{ apiUpdateFields }}
};
const {{ nameCamel }} = await {{ nameCamel }}Service.update({{ nameCamel }}Data);
res.json({{ nameCamel }}Mapper({{ nameCamel }}));
} catch (error) {
const message = getErrorMessage(error);
console.error(`Failed to update {{ nameLower }}: ${message}`);
res.status(400).json({
error: 'Failed to update {{ nameLower }}',
});
}
},
]);
app.delete('/{{ nameKebab }}/:{{ primaryKey }}', [
isAdmin,
async (req: RequestContext, res: Response) => {
try {
const {{ primaryKey }} = req.params.{{ primaryKey }};
await {{ nameCamel }}Service.delete({{ primaryKey }});
res.status(200);
res.send();
} catch (error) {
const message = getErrorMessage(error);
console.error(`Failed to delete {{ nameLower }}: ${message}`);
res.status(400).json({
error: 'Failed to delete {{ nameLower }}',
});
}
},
]);
app.get('/{{ nameKebab }}/list', [
isAdmin,
async (req: RequestContext, res: Response) => {
try {
const {{ nameCamel }}s = await {{ nameCamel }}Service.getAll();
const formatted{{ nameFirst }}s = {{ nameCamel }}s.map({{ nameCamel }}Mapper);
res.json(formatted{{ nameFirst }}s);
} catch (error) {
const message = getErrorMessage(error);
console.error(`Failed to get {{ nameLower }}s: ${message}`);
res.status(400).json({
error: 'Failed to get {{ nameLower }}s',
});
}
},
]);
app.get('/{{ nameKebab }}/:{{ primaryKey }}', [
isAdmin,
async (req: RequestContext, res: Response) => {
try {
const {{ nameCamel }} = await {{ nameCamel }}Service.get(req.params.{{ primaryKey }});
res.json({{ nameCamel }}Mapper({{ nameCamel }}));
} catch (error) {
const message = getErrorMessage(error);
console.error(`Failed to get {{ nameLower }}: ${message}`);
res.status(400).json({
error: 'Failed to get {{ nameLower }}',
});
}
},
]);

View file

@ -0,0 +1,16 @@
Resources:
{{ nameCamel }}Table:
Type: AWS::DynamoDB::Table
DeletionPolicy: ${self:custom.deletionPolicy.${opt:stage}}
UpdateReplacePolicy: ${self:custom.updatePolicy.${opt:stage}}
Properties:
TableName: ${env:APP_NAME}-${opt:stage}-{{ nameKebab }}
AttributeDefinitions:
- AttributeName: {{ primaryKey }}
AttributeType: S
KeySchema:
- AttributeName: {{ primaryKey }}
KeyType: HASH
BillingMode: PAY_PER_REQUEST
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true

View file

@ -0,0 +1,37 @@
Api{{ nameFirst }}:
handler: src/baseblocks/{{ nameKebab }}/{{ nameKebab }}-api.handler
events:
- http:
path: /{{ nameKebab }}/{any+}
method: ANY
authorizer: # https://www.serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoints-with-aws_iam-authorizers
type: COGNITO_USER_POOLS
authorizerId:
Ref: ApiGatewayAuthorizer
cors:
origin: ${self:custom.apiCorsOrigin}
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
allowCredentials: false
- http:
path: /{{ nameKebab }}
method: ANY
authorizer: # https://www.serverless.com/framework/docs/providers/aws/events/apigateway#http-endpoints-with-aws_iam-authorizers
type: COGNITO_USER_POOLS
authorizerId:
Ref: ApiGatewayAuthorizer
cors:
origin: ${self:custom.apiCorsOrigin}
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
allowCredentials: false

View file

@ -0,0 +1,3 @@
[
{{ seedData }}
]

View file

@ -0,0 +1,14 @@
import { {{ nameFirst }} } from '@baseline/types/{{ nameKebab }}';
import { getDynamodbConnection } from '@baselinejs/dynamodb';
import { ServiceObject } from '../../util/service-object';
const dynamoDb = getDynamodbConnection({
region: `${process.env.API_REGION}`,
});
export const {{ nameCamel }}Service = new ServiceObject<{{ nameFirst }}>({
dynamoDb: dynamoDb,
objectName: '{{ nameFirst }}',
table: `${process.env.APP_NAME}-${process.env.NODE_ENV}-{{ nameKebab }}`,
primaryKey: '{{ primaryKey }}',
});

View file

@ -0,0 +1,7 @@
import { {{ nameFirst }} } from '@baseline/types/{{ nameKebab }}';
export const {{ nameCamel }}Mapper = (data: {{ nameFirst }}): {{ nameFirst }} => {
const {{ nameCamel }}: {{ nameFirst }} = {{{ mapperFields }}
};
return {{ nameCamel }};
};