Primer-Token

Quick task implementation

Requirements

Python 3.7+ is required to run the application (using dataclasses and other nice-to-have python scaffolding)

Installation

  • To install, clone the repository locally: git clone https://github.com/an-dev/primer-tokenizer
  • Create virtualenv: python3.8 -m venv .venv
  • Activate virtualenv: source .venv/bin/activate
  • Install dependencies: pip install -r requirements.txt
  • Migrate data/setup db python manage.py migrate

Testing

Test via django built in command: python manage.py test

Usage

Note: If you use primer-token.herokuapp.com as a host, beware that the heroku puts the server to sleep after 30 minutes of inactivity, and your first call might timeout as the workers are being turned on.

The project was developed with Stripe, use any of the of their sandbox cards https://stripe.com/docs/testing#cards

Tokenize credit card

Request

curl --request POST \
  --url http://localhost:8000/api/tokenize/ \
  --header 'Content-Type: application/json' \
  --data '{
        "number": "4242424242424242",
        "expiry_month": 10,
        "expiry_year": 2021
    }'

Successful Response

{
    "token": "tok_xxxxxx"
}

Execute sale with token (obtained from API call above)

Request

curl --request POST \
  --url https://localhost:8000/api/sale/ \
  --header 'Content-Type: application/json' \
  --data '{
        "token": "tok_xxxxxx",
        "amount": 45000,
        "description": "Just your average description for a charge",
        "currency": "usd"
    }'

Successful Response

{
    "receipt_url": "https://pay.stripe.com/receipts/acct_xxxxx/ch_yyyyyyy/rcpt_zzzzz", # You can view the transaction/receipt here btw
    "transaction_id": "txn_xxxxx"
}

Notes, Technical decisions et all

Choice of processor/connector

The project is heavily influenced by Stripe, as it was used as main/default choice as a connector, but it opens to possibility of implementing other connectors.

Data storage

The project doesn't store any Customer/Card information, as it wasn't one of the explicit features requested by the task but this would be easily implementable.

customer 1 -> n card

card 1 -> n tokens (single use)

In the above scenario a "returning" user/card details would no create a new card but return:

  • a non used token related to the card details inserted
  • a new token

Enpoint Authorization/Authentication

If this was a publicly exposed API some sort of Authorization would be needed for a potential developer (along with other safeguards like rate limiting etc...)

Testing and logging

A minimalistic approach to testing was taken, using cassettes to speed up tests that may require external API calls to speed up test cases. Potentially more comprehensive tests would be written (on the connectors for example).

As for logging and exception handling, common or expected errors are catched while leaving unexpected events bubble up (in a production environment we'd be notified about these with a Sentry-like system)

References

Web pages used/consulted while building the script

https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset

https://www.django-rest-framework.org/api-guide/testing/#testing

https://stackoverflow.com/questions/31685688/is-allowed-hosts-needed-on-heroku