T.E.S: Transactional Email Service, a take-home assessment.
In order to prevent downtime during an email service provider outage, you're tasked with creating a service that provides an abstraction between at least two different email service providers. This way, if one of the services goes down, you can quickly fail over to a different provider without affecting your customers.
MVP:
- A
/email
endpoint that acceptsPOST
requests in order to send an email - Safe handle of HTML content in the body of the email
- Basic Responses to
/email
signaling success or failures - Safe handling of unsupported endpoints
- Safe handling of unsuported METHOD to
/email
- Safe handling of non-json request body data
- Service provider outage detection and notification/timeouts
- Configurable service provider in order to recover quickly from a potential outage
Additional
- Informative responses to
/email
endoing with detailed failure messages, see error responses - Safe handling of CORS requests since endpoint is public
- Fail fast if config is bad or missing info, informing of the error
- Fail fast if API keys for service providers are not set, informing of the error
- enable https
- Verbose logging for debugging purposes
- DOS attack detection, too many requests (429 Code)
- Large request body processing error detection (413)
For testing purposes (Additional)
- Potentially, a method to simulate service provider failures.
- Potentially, a method to check if a service provider is up or down.
npm run dev
Coding Improvements:
- Abstract axios library in order to make it easy to switch out.
- swich dev branch to main as the default branch.
- Add more documentation, e.g. jsdoc
- use dotenv for storing api keys ensuring it's in the .gitignore.
- Unit tests for non-business logic code
- Better organization for the rest interface, e.g. having a routes file.
- What happens if both/all services providers are down?
- Does it suffice to simply log an error to the console when a service provider is down?
- Should we worry about bounced messages?
- Should a user be able to email him/herself?
- Is there a maximum length for the body of the email?
- Install nvm+npm+node
- Sign up and obtain an API key from SendGrid and add a verified sender
- Sign up and obtain an API key from MainGun
- Install your favorite http client testing app: postman, insomnia
Below are the steps to build the application:
- Clone the repo:
git clone https://github.com/javoltaire/tha_rupa_tes.git
- Install dependencies:
npm install
- Modify
/src/config/config.dev.js
to update configs for service providers. e.g. a valid domain from your mailgun account.
An HTTP server that listens on a pre-configured port. See Endpoints for a list of routes. To run the server, use:
$SG_API_KEY=<SENDGRID_API_KEY> MG_API_KEY=<MAILGUN_API_KEY> npm run dev
NOTE the SG_API_KEY
and MG_API_KEY
environment variables
In case of a provider (courier) is down, modify /src/config/config.dev.js
to change email_providers.default
to sendGrid
or mailGun
.
Now open up your favorite http client and make post request to /email
. Keep scrolling for the endpoints documentation section.
- Despite using a verified sender through send grid, you may still get an unauthorized response. This will need to be further investigated.
This project was implemented using clean architecture by Robert C. Martin (Uncle Bob).
TODO: <Show file structure here.>
- Node.js
- yup (for validation)
- restify (quick api setup)
- axios (http client library)
- npm
- nvm
- babel
Send an email using one of our providers
URL: /email
Method: POST
Auth required: NO
Request Body:
Parameter | type | constraints | description |
---|---|---|---|
to |
string |
[required][email] |
The address of the recipient of the email |
to_name |
string |
[required] |
The name of the recipient of the email |
from |
string |
[required][email] |
The address of the sender of the email |
from_name |
string |
[required] |
The name of the sender of the email |
subject |
string |
[required] |
The subject line of the email |
body |
string |
[required] |
The body of the email |
Request Body Example:
{
"to": "fake@example.com",
"to_name": "Mr. Fake",
"from": "no-reply@fake.com",
"from_name":"Ms. Fake",
"subject": "A message from The Fake Family",
"body": "<h1>Your Bill</h1><p>$10</p>"
}
Code: 200 OK
Content:
{
"message": "Email sucessfully sent"
}
Code: 400 Bad Request
Content:
{
"message": "Invalid request body: check content and try again"
}
OR
Code: 415 Unsupported Media Type
Content:
{
"message": "Unsupported Content Type: only JSON type allowed"
}
OR
Code: 405 Method Not Allowed
Content:
{
"message": "Unsupported Request Method: only POST method allowed"
}
OR
Code: 500 Internal Server Error
Content:
{
"message": "Unable to complete request, please try again later"
}