questionsandanswers.com

module
v0.0.0-...-77f07be Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2020 License: MIT

README

questionsandanwsers.com

Coding exercise for NuORDER

This is a simple web application, with an API backend written in go (golang) and a frontend written in React. The frontend was bootstrapped using create-react-app.

Setting up a development environment

First, build the API server:

$ cd go
$ make

Next, install JS dependencies for the front end:

$ cd ../js
$ yarn install

Then, in a spearate terminal window, run the dev JS server. Note: the purpose of this to take advantage of hot reloading while developing. You will not be running a node server in production.

$ cd js
$ yarn run dev

By default, this will start the dev server on port 3000. If you have something else running on that port, it will choose a different port, of which you should make note and use in the next step.

Finally, start up the API server:

$ cd ../go
$ ./questionsandanswers -port 8080 -default-proxy http://localhost:3000/

Now, you can point your browser to http://localhost:8080/ and go to town.

Production deployment

Production deployment is a pretty bare bones operation for this exercise. In the project's root directory, just run make. This will build everything, and package it up in a gzipped tarfile named build/questionsandanswers-0.0.1.tar.gz. Copy that tarfile to your production server and unpack it. Then, in the unpacked directory, run the following command:

$ ./bin/startup.sh

The app should now be available at http://YOURHOST:8080/

API Calls

List questsions & answers
GET /api/questions?<PARAMS>

Query parameters (URL encoded):

  • count integer

    Maximum number of results to return per page

    Default: 10

    Max: 100

  • page integer

    Page number in result set (where first page is zero)

    Default: 0

  • sort string

    Sort order for results. Can be one of the following:

    • questionDate ascending date question was originally asked
    • -questionDate descending date question was originally asked
    • answerDate ascending date question was most recently answered
    • -answerDate descending date question was most recently answered

    Default: -questionDate

Response structure:

{
    "meta": {
        "pageNum": 3,
        "pageSize": 100,
        "resultCount": 100,
        "sortOrder": "-questionDate",
        "prevPage": "/api/questions?count=100&page=2&sort=-questionDate",
        "thisPage": "/api/questions?count=100&page=3&sort=-questionDate",
        "nextPage": "/api/questions?count=100&page=4&sort=-questionDate",
        "totalPages": 10,
        "totalResults": 950
    },
    "results": [
        {
            "id": "12345678-90ab-cdef-1234-567890abcdef",
            "question": "Why does it always rain on me?",
            "questionDate": 1600622848050,
            "answer": "Because you lied when you were seventeen.",
            "answerDate": 1600622876227
        },
        {
            "id": "abcdef12-3456-7890-abcd-ef1234567890",
            "question": "Who will save your soul?",
            "questionDate": 1600622818050
        }
    ]
}
Get question by ID
GET /api/question/12345678-90ab-cdef-1234-567890abcdef

Response structure:

{
    "id": "12345678-90ab-cdef-1234-567890abcdef",
    "question": "Why does it always rain on me?",
    "questionDate": 1600622848050,
    "answer": "Because you lied when you were seventeen.",
    "answerDate": 1600622876227
}
Create a question
POST /api/question

The request body should be the plain text of the question (text/plain).

Response structure:

{
    "id": "abcdef12-3456-7890-abcd-ef1234567890",
    "question": "Who will save your soul?",
    "questionDate": 1600622818050
}
Answer a question
PUT /api/question/12345678-90ab-cdef-1234-567890abcdef

The request body should be the plain text of the question (text/plain).

Response structure:

{
    "id": "12345678-90ab-cdef-1234-567890abcdef",
    "question": "Why does it always rain on me?",
    "questionDate": 1600622848050,
    "answer": "Because you lied when you were seventeen.",
    "answerDate": 1600622876227
}

Database schema

Table question
  • id VARCHAR(36) NOT NULL

    String representation of a UUID. This is the table's primary key

  • question TEXT NOT NULL

    The question text

  • question_date BIGINT NOT NULL

    The time (in milliseconds since the Unix epoch) the question was originally asked

  • answer TEXT

    The text of the most recent answer. May be null if the question has not yet been answered.

  • answer_date BIGINT

    The time (in milliseconds since the Unix epoch) the question was most recently answered. May be null if the question has not yet been answered.

Further Improvements

Had time permitted, here are the areas I would focus on for improvement:

Tests

Unit tests & integration tests are a must for production ready software. But they take time to write.

TLS

No publicly available website should run without TLS (HTTPS) encryption. Let's Encrypt offers easy, free certificates. However, those certificates are only valid for publicly-accessible domain names, which makes development on localhost more problematic.

Database

Time and resource constraints of the exercise required an embedded database (SQLite) so that the code could run in a self contained package. Were this a production system, I would have built the database using Cassandra or DynamoDB (if using AWS). The database schema is a straight forward key-value store, and does not rely on any relational queries, so such a migration would require no change to the queries.

Docker / Lambda

Depending on the deployment environment, it would make more sense to bundle this app up into a docker container. If deploying in AWS, the API endpoints could be split into separate Lambda functions, and hosted behind API Gateway, with the front end code served from S3.

Logging

In a production environment, logs (access & error logs) should be sent to a log aggregation and analysis service, like Graylog or LogStash.

Feature enhancements
  • I would have liked to support markdown syntax for the questions and answers. This would not change much about the backend (database or API) but would have required some additionaly front-end work.
  • I would like to have an audit trail or wiki-like versioning for the answers, but this was explicitly out of scope.
  • Questions and answers should be tied to user accounts, but this was explicitly out of scope.
  • The user who originally asked a question should be able to accept an answer and prevent further edits.
  • There should be a search feature
  • The front-end should expose a method to change the sort order

Directories

Path Synopsis
go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL