-
Notifications
You must be signed in to change notification settings - Fork 0
/
createHttpFunction.ts
99 lines (88 loc) · 2.99 KB
/
createHttpFunction.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import type { Topic } from '@google-cloud/pubsub'
import type { EmailData } from '@suin/email-data'
import { newEventData } from '@suin/event-data'
import type { Request, Response } from 'express'
import { parseEmailData } from './parseEmailData'
import { FormData, parseFormData } from './parseFormData'
import { parseSendgridPayload, SendgridPayload } from './sendgridPayload'
export const createHttpFunction = ({
topic,
logger = defaultLogger,
}: Dependencies) => async (
req: Pick<Request, 'method' | 'headers' | 'rawBody'>,
res: Pick<Response, 'send' | 'end' | 'status'>,
): Promise<void> => {
if (req.method !== 'POST') {
return res.status(405).send('Only POST method is supported').end()
}
// Generate correlationId
const correlationId = generateCorrelationId(req.headers, logger)
logger.info(`CorrelationId generated: ${correlationId}`, { correlationId })
// Parses form data
let formData: FormData
try {
formData = await parseFormData(req)
} catch (error) {
logger.error('Failed to parse the form data', { error })
return res.status(400).send(error.message).end()
}
logger.info(`Form data was parsed`)
// Parses the SendGrid form data
let sendgridPayload: SendgridPayload
try {
sendgridPayload = parseSendgridPayload(formData)
} catch (error) {
logger.error('Failed to parse the SendGrid form data', { error, formData })
return res.status(400).send(error.message).end()
}
logger.info('SendGrid payload was parsed')
// Parses the email
let emailData: EmailData
try {
emailData = await parseEmailData(sendgridPayload.email)
} catch (error) {
logger.error('Failed to parse email source', {
email: sendgridPayload.email,
})
return res.status(400).send(error.message).end()
}
logger.info('The email source was parsed')
// Publishes email
try {
const event = newEventData({ correlationId, data: emailData })
await topic.publish(Buffer.from(JSON.stringify(event), 'utf8'))
logger.info(`Successfully published the email to topic ${topic.name}`)
} catch (error) {
logger.error(`Failed to publish the email to topic ${topic.name}`, {
emailData,
})
res.status(500).send('Something wrong')
}
res.status(200).send('OK')
}
const generateCorrelationId = (
headers: Request['headers'],
logger: Logger,
): string => {
const id = headers['function-execution-id']
if (typeof id !== 'string') {
logger.info('The request header is wrong', { headers, id })
throw new Error(
'function-execution-id header in the request is required and must be a single string value',
)
}
return id
}
const defaultLogger: Logger = {
error(message: string, meta?: unknown): void {
console.error(JSON.stringify({ message, meta }))
},
info(message: string, meta?: unknown): void {
console.info(JSON.stringify({ message, meta }))
},
}
export type Dependencies = {
readonly topic: Pick<Topic, 'publish' | 'name'>
readonly logger?: Logger
}
export type Logger = Pick<Console, 'info' | 'error'>