This minimal REST API stores person
records. Each person
is uniquely
identifiable by their associated person_id
(UUID) and version
. Once
a unique person
is created, updates to the person
's attributes
result in the creation of a new record with the same person_id
, but
with a new version
attribute. Only the most current version
of a
person
can be updated. When a person
is updated, the API enforces
that there are changes compared to the current version
. It does not,
however, verify that the new version
is unique across all versions for
the associated person_id
. The most current version
of a person
can
be deleted.
Bulk queries are not supported at this time.
This project was built using Python3.8, the FastAPI framework, and PostgreSQL, all running stress-free in Docker.
Why FastAPI? There's been a lot of talk about this framework and I've been eager to test drive it. It did not disappoint. It has superior async support--there's absolutely no need to think about event loops. FastAPI uses mandatory data validation via pydantic, which provides smooth error handling and enables very nice auto-generated documentation. Recommend. 10/10. Would use again.
These instructions assume the host is running MacOS or Linux and Docker is installed.
To run,
- clone repo
- cd into project root, then...
$ docker-compose up -d --build
Test the service is running by navigating to http://localhost:8002/docs.
To run the unit tests...
$ tox --
There is currently no authentication. The PostgreSQL credentials are hard-coded where needed (and checked into version control). This is deliberate, as this is only a POC. If this were going to be used in production, credentials never would have been checked into version control.
Remove the hardcoded DB credentials and change the login and password prior to public use.
When the service is running, detailed Swagger/OpenAPI documentation
can be found at the /docs
endpoint.
check it out here. Or the ReDoc version
here.
Overview of Available REST Endpoints:
ENDPOINT | ACTION | REQ. PARAM | OPTIONAL PARAMS | BODY REQUIRED |
---|---|---|---|---|
/person/ | POST | None | None | Yes |
/person/ | GET | person_id | version | No |
/person/ | PUT | person_id | None | Yes |
/person/ | DELETE | person_id | None | No |
/persons/ | GET | None | None | No |
Sample curls:
POST /person/
$ curl -X POST "http://localhost:8002/person/" -H "accept: application/json" -H "Content-Type: application/json" -d '{"first_name":"guido","last_name":"van rossum","email":"guidovr@python.com","age":64}' -i
GET /person/{person_id}
$ curl -X GET "http://localhost:8002/person/843651c0-4e05-4960-a274-95578912bfe1" -H "accept: application/json" -i
PUT /person/
$ curl -X PUT "http://localhost:8002/person/" -H "accept: application/json" -H "Content-Type: application/json" -d "{'person_id':'843651c0-4e05-4960-a274-95578912bfe1','email':'guidovr@python3.com'}" -i
DELETE /person/{person_id}
curl -X DELETE "http://localhost:8002/person/843651c0-4e05-4960-a274-95578912bfe1" -H "accept: application/json" -i
GET /persons/
$ curl -X GET "http://localhost:8002/persons/" -H "accept: application/json" -i
The project's Swagger Documentation contains sample request and response objects, as well as the ability to interactively test the API.
A note on mandatory trailing /
's in requests. In an effort to keep
the swagger clean since this is just a POC, I chose not to go with
either of the two inelegant options
discussed here.
TL;DR: changes to a FastAPI dependency broke standard regex in routes.
- DB Transactions. Currently no DB queries are transactional/atomic. The downside to this is obvious. In addition to increasing data integrity, using transactional, atomic queries would reduce the complexity of the handler code.
- Relational vs Non-Relational. Lots of thoughts here.
- Delete returns success even if no target record was found. There are varying opinions on this behavior. From a security standpoint it could be considered a feature, from a usability standpoint it could be viewed as a bug.
- Cache. Caching the latest version of each person with some TTL will reduce the need for the most common DB query.
- Testing. This needs integration tests. And more unit tests!!
- Logging
This project mostly conforms to the standards in PEP-8. Max line length is extended to 88 characters, which is Black's default line-length.