Dog to Cat API ~ Powered by NestJS Framework
$ git clone git@github.com:desoleary/dog-to-cat-nestjs-api.git
$ cd dog-to-cat-nestjs-api
$ yarn install
# development
$ yarn run start
# NOTE: Open a new console tab
$ open http://localhost:3000/api # Should open app in your browser
# 1. Click on POST /dog2cat
# 2. Click on Try it out
# 3. replace "Request body" e.g.
# Example Request body:
{
"payload":{
"a":1,
"b": "dog",
"c": "dog dog",
"d": "cat",
"e": "dog cat",
"f":{
"a": "dog",
"list":[
{
"x1": "dog",
"x2": "cat",
"x3": "doggdog"
}
]
}
}
}
curl -X 'POST' \
'http://localhost:3000/dog2cat' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"payload":{
"a":1,
"b": "dog",
"c": "dog dog",
"d": "cat",
"e": "dog cat",
"f":{
"a": "dog",
"list":[
{
"x1": "dog",
"x2": "cat",
"x3": "doggdog"
}
]
}
}
}'
# watch mode
$ yarn run start:dev
# production mode
$ yarn run start:prod
# unit tests
$ yarn run test
# e2e tests
$ yarn run test:e2e
# test coverage
$ yarn run test:cov
- Please Note ~ I have never tried out
nestjs
but I felt that this project would be a great opportunity to try it out based on a small amount of research today. There might well be mistakes/omissions but I do hope it showcases some of my thought process. - In order to cater for arbitrary JSON payloads I have gone with the following solution:
- Flatten json payload in order to greatly reduce the complexity of traversing deeply nested paths
- map use of a callback mechanism for each deep path and check if value is precisely
dog
then replace value withcat
- preserve any other values
Example walkthrough:
const originalPayload = {
a: 1,
b: 'dog',
c: 'dog dog',
d: 'cat',
e: 'dog cat',
f: { a: 'dog', list: [{ x1: 'dog', x2: 'cat', x3: 'doggdog' }] },
}
// flattened payload in order to simplify traversal of JSON payload
const flattenedPayload = {
'a': 1,
'b': 'dog',
'c': 'dog dog',
'd': 'cat',
'e': 'dog cat',
'f.a': 'dog',
'f.list.0.x1': 'dog',
'f.list.0.x2': 'cat',
'f.list.0.x3': 'doggdog',
}
// we iterate through each flattened key value pairs and modify those that match our criteria e.g. /^dog$/
const flattenedPayloadWithModifications = {
'a': 1,
'b': 'cat',
'c': 'dog dog',
'd': 'cat',
'e': 'dog cat',
'f.a': 'cat',
'f.list.0.x1': 'cat',
'f.list.0.x2': 'cat',
'f.list.0.x3': 'doggdog',
}
// undot/hydrate modified flattened payload
const finalizedPayload = {
a: 1,
b: 'cat',
c: 'dog dog',
d: 'cat',
e: 'dog cat',
f: { a: 'cat', list: [{ x1: 'cat', x2: 'cat', x3: 'doggdog' }] },
}
Project is mainly for demonstration purposes I am avoiding such optimisations/maintainability
- streaming payload in order to work on chunks of data
- Authentication
- timeouts
- for very large payloads it might make sense to offload to the likes of a message queue
- Cypress E2E testing