Skip to content

mssola/todo

Repository files navigation

ToDo Build Status GoDoc

## About this application

This application has a simple job: handle my "To Do list". This might seem trivial but I got to a point where my To Do list was a scrambled mess that was scattered throughout my system. To fix this situation I've built a service that has the following specifications:

  • There only exists one user in the database.
  • The "To Do" list is organized in topics. Topics can be created, deleted, renamed, updated, etc.
  • A topic has contents, that are written in Markdown.

This application implements two things: a web application and an API layer.

### The Web Application

The web application has a quite minimalistic design and it only consists of two different pages:

  1. The login page.
  2. The topics page. This is the main page and in it the user can create new topics, read their contents, update them, etc.

The style for this web application has been taken from Reddit's one (the list of topics in this application has the same style as the list of multireddits). The markdown being shown has a similar style as the one from Github. A snapshot:

The main page

The JSON API

This application also implements a JSON API. This API can be accessed by setting application/json in the Content-Type or the Accept header of the request. First of all, you have to login with the application. In order to do so, you have to perform a POST HTTP request to /login with the following body:

{
  "name":     "name-of-the-user",
  "password": "password-for-this-user"
}

If everything was ok, the response should only be a JSON object with the token key. The value for this key has to be used on every request afterwards by adding it to the URL query part. With this in mind, we can now call any method of this simple REST API:

Method Path Keys in the JSON body Response
GET /topics - Array of Topics
POST /topics name Topic
GET /topics/{topicId} - Topic
PUT or PATCH /topics/{topicId} name or contents Topic
DELETE /topics/{topicId} - Message

The fourth method is the update method. It accepts either the name or the contents, but not both parameters at the same time. We might want to pass the name key when renaming a topic. We will pass the contents key if we want to update the contents of a topic. Moreover, the last method is the delete method. This method responds with a Message object. A Message object contains the key msg on success, and the error key on error.

Let's see a quick example (cURL with the --trace-ascii option):

0000: POST /topics?token=6b6c0542-0891-4614-5dd8-92ce443dbcaf HTTP/1.
0040: 1
0043: User-Agent: curl/7.38.0
005c: Host: localhost:3000
0072: Accept: */*
007f: Content-Type: application/json
009f: Content-Length: 17
00b3:
=> Send data, 17 bytes (0x11)
0000: {"name": "topic"}

The create method will respond with the newly created Topic on success:

{
  "id":         "ec654b88-e227-47bb-6254-60b77329732e",
  "name":       "topic",
  "contents":   "",
  "created_at": "2014-10-07T08:37:05.424276522+02:00",
  "markdown":   ""
}

So, let's explain the Topic object. The id, name and created_at columns are quite self-explanatory. The contents column exposes the raw data of this object. The markdown object contains the HTML code that has been produced after rendering the markdown of the contents column.

## Getting this application up and running

This application uses the Go programming language and some awesome packages like negroni, gorilla/mux, blackfriday, etc. Moreover, it uses PostgreSQL for the database. In order to configure the database, you can use the following environment variables:

  • TODO_DB_USER, defaults to "postgres".
  • TODO_DB_NAME, defaults to "todo-dev".
  • TODO_DB_PASSWORD, defaults to "".
  • TODO_DB_HOST, defaults to "localhost".
  • TODO_DB_SSLMODE, defaults to "disable".

The port in which this application is listening into is set by the environment variable TODO_PORT. By default it runs on the port 3000.

You might want to use the given docker compose setup as given in the docker-compose.yml file. Note that it will create two nodes: web and db. The db node uses the official Postgres image. Make sure to understand how it works. The db node has to be initialized with the given command inside of the container:

$ psql -U postgres <name-of-db> < /tmp/db/tables.sql

There is also a Dockerfile providing an up-to-date image of the application (mssola/todo:latest on the Docker Hub). However, if you want to build this manually, you can type:

$ godep go build && ./todo

Secure connection

Since you usually want to run this through a safe connection, this application also allows the deployer to set the following environment variables:

  • TODO_KEY_PATH: the path to your key file.
  • TODO_CERT_PATH: the path to the certificate file.

Moreover, the .gitignore file ignores the docker-compose.production.yml file. You might want to use this file to run a customized version of docker-compose.yml file. An example could be:

web:
  image: mssola/todo:latest
  volumes:
    - /path/to/certs:/path/to/certs
  ports:
    - 443:3000
  environment:
    TODO_DB_NAME: todo-production
    TODO_DB_HOST: todo_db_1
    TODO_KEY_PATH: /path/to/certs/todo.key
    TODO_CERT_PATH: /path/to/certs/todo.crt
  links:
    - db

db:
  image: library/postgres:9.4
  volumes:
    - ./db:/tmp/db
  environment:
    POSTGRES_DB: todo-production

## License

Copyright © 2014-2017 Miquel Sabaté Solà

This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.