Egyptian national ID validator, decoder and metadata extractor, it provides single RESTful API for validating a national ID and extracting as much information as it can from that ID, this Wikipedia page and this blog was used as a reference for the implementation.
FastAPI for its high performance, automatic interactive documentation support, concise and simple design, Pydantic for representation and validation of the national ID and the metadata it encodes, pytest for running the unit tests.
i tried to follow the "12 Factor App" methodology as much as i can by using the following tools/technologies.
- GIT for applying the following factor/s:
- Code base version control and tagging service's releases.
- Docker for applying the following factor/s:
- Explicitly declare and isolate dependencies.
- Enviroment based configuration.
- Robust and easy build, release and run process.
- Publish the service as a one or more stateless containers/processes.
- Container/process/service export via port binding.
- Fast and easy container/service startup and graceful shutdown.
- Keeping development, staging, and production as similar as possible.
- Loguru for applying the following factor/s
- logging, specially for logging unexpected errors or exceptions (no unexpected exceptions or failures should went unnoticed specially on production env).
requirements.txt
the project requirements with version pinning.manage.sh
provides an interface for running, deploying, restarting, and killing the service's container.service/utils/utils.py
shared utilites that can be reused throughout the code to avoid code repetition.service/models.py
the Pydantic Models definitions.service/main.py
defines theFastAPI()
instance and hooks the service'sAPIRouter()
instances with it.service/routers/enid.py
defines the endpoints that are specific to the egyptian national ID operations (decoding, validation, etc...).- currently the module defines a single RESTful endpoint on its
APIRouter()
instance for handling the validation and decoding of the egyptian national ID.
- currently the module defines a single RESTful endpoint on its
service/exceptions/exceptions.py
defines the custom exceptions which are specific to the app domain.serivce/tests/
defines the unit tests.
Why did i use HTTP POST dialect/method for the single RESTful endpoint and not other HTTP methods like GET ?
Hmm, although the request here (validate and decode the egyptaion national ID) is idempotent, it might be the case that we don't want the national ID to appear in the web servers logs as part of the URL's query parameters.
Endpoint's path: /enids/sieve
PS: I did not use HTTPS to keep the service review simple and it's assumed that this service might be used as a micro-service on the internal AWS network so actually going w/o HTTPS would improve the request's response time as there will be no TLS handshake, certificate validation etc...
./manage.sh unittests
Build the service's container image (build operation includes the purge of dangling/residue intermediate container images
./manage.sh build
./manage.sh run
./manager kill
./manage deploy
- Go to
http://127.0.0.1:8000/docs
in your web browser for Swagger UI - Go to
http://127.0.0.1:8000/redoc
in your web browser for ReDoc UI
Try it out with CURL
curl -X 'POST' \
'http://127.0.0.1:8000/enids/sieve' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"enid": "29808051301512"
}'
Try it out with Python's requests
import requests
ENDPOINT_URL = 'http://localhost:8000/enids/sieve'
payload = {"enid": "29808051301512"}
resp = requests.post(ENDPOINT_URL, json=payload)
assert resp.status_code == 200
resp.json()