snippet-api

This is an API web server that accepts a snippet of text and makes that snippet available at a URL. Each snippet should be available as text at a URL until it expires. Snippets expiry should be extended when they are accessed.

Brief Documentation

The snippets are currently being stored in a SQLite file (app.db), which was the quickest solution and doesn't need a database server, like PostgreSQL or MySQL would.

The two endpoints currently available are [POST] /api/snippets and [GET] /api/snippets/<int:id>, as detailed below:

[POST] /api/snippets

The request to store the snippet should accepts the fields below:

Parameters:

  • name: string (mandatory), the name of the snippet
  • expires: string (mandatory), the expiration date of the snippet. Please prefer to use a widely known string representation for datetime, such as ISO 8601 (YYYY-MM-DDTHH:MM:SS.mmmmmm)
  • snippet: string (mandatory), the snippet text itself
  • password: string (optional), can be used if the user decides to edit the snippet

This request stores the snippet and replies with a JSON representing the snippet, as well as the URL where the snippet can be read.

Response (status_code: 201):

{
  "_links": {
    "self": "/api/snippets/1"
  },
  "expires": "2020-07-01T04:21:41",
  "id": 1,
  "name": "Test Snippet 2",
  "snippet": "Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum"
}

The URL to the recently created resource also returns as in the Location header, with the full path like "http://127.0.0.1:5000/api/snippets/1" (when executed from localhost)

[GET] /api/snippets/<int:id>

This request returns the snippet as a JSON, as well as the URL where the snippet was read.

Response (status_code: 200):

{
  "_links": {
    "self": "/api/snippets/1"
  },
  "expires": "2020-07-01T04:21:41",
  "id": 1,
  "name": "Test Snippet 2",
  "snippet": "Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum"
}

Important info about this endpoint:

  • The snippets can only be accessed at the [GET] /api/snippets/{id} endpoint before they expired. After expiration, the API will answer with a 403 status code.
  • Snippets expiration date will be extended every time they are accessed. The default extension time is 6 hours, but it can be edited from the .flaskenv file, located in the project root folder.

The URL to the recently created resource also returns as in the Location header, with the full path like "http://127.0.0.1:5000/api/snippets/1" (when executed from localhost)

[PUT] /api/snippets/<int:id>

This allows editing a snippet that was created with a password (optional field). The following fields can bve used in the PUT request:

Parameters:

  • name: string (optional), the name of the snippet
  • expires: string (optional), the expiration date of the snippet. Please prefer to use a widely known string representation for datetime, such as ISO 8601 (YYYY-MM-DDTHH:MM:SS.mmmmmm)
  • snippet: string (optional), the snippet text itself
  • password: string (mandatory), can be used if the user decides to edit the snippet

Please notice the PUT request can be used to change the expiration date of the snippet.

It will return the snippet as a JSON, as well as the URL where the snippet was read.

Response (status_code: 200):

{
  "_links": {
    "self": "/api/snippets/1"
  },
  "expires": "2020-07-01T04:21:41",
  "id": 1,
  "name": "Test Snippet 2",
  "snippet": "Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum Lorem ipslum"
}

Important info about this endpoint:

  • The snippets can only be accessed at the [GET] /api/snippets/{id} endpoint before they expired. After expiration, the API will answer with a 403 status code.
  • Snippets expiration date will be extended every time they are accessed. The default extension time is 6 hours, but it can be edited from the .flaskenv file, located in the project root folder.

Dependencies

  • flask: a micro web framework written in Python
  • flask-sqlalchemy: Flask bridge for SQLAlchemy, a Python SQL toolkit and Object Relational Mapper (ORM)
  • flask-migrate: a Flask extension that handles SQLAlchemy database migrations
  • flask-marshmallow: used to convert between Python objects and json serializable structures
  • marshmallow-sqlalchemy: Used to connect marshmallow with SQLAlchemy
  • python-dotenv: Used to store the environment variables, that wouldn't be comitted to the repo

Installation

  • $ pipenv shell: activate the virtual environment
  • $ pipenv install: install the dependencies
  • $ flask db upgrade: migrate the database to the head version

Configuration

In order to run the project you will need a .flaskenv file. I've comitted a development version of the .flaskenv file, although this is not a recommended approach for a production project.

Running the project

From the route directory, make sure your virtual environment is active and then execute flask:

  1. $ pipenv shell
  2. $ flask run

Future improvements

Here is a list of improvements that would likely be needed for a production application:

  • Unit tests and API tests
  • Change SQLite to PostgreSQL, since the PostgreSQL includes: authentication system, ACID compliancy, Multiple Access, etc.
  • Move the snippets fromn a SQLite database to separated files
  • CI/CD
  • Add API versioning (e.g. v1, v2, etc.)