This is my solution to a recruitment task
The app is deployed on heroku.com,
it runs on https://notifai-task.herokuapp.com
.
The app should use Python 3.8.
To run the app one needs to set up the following environment variables:
Variable | Description |
---|---|
MONGODB_URI |
An URI to connect to the database. |
SECRET_KEY |
A secret key used, to encode access tokens. |
PASSWORD |
A password to obtain the access token. |
TOKEN_EXP_TIME |
Time after which the token expires, in minutes |
DATABASE_NAME |
The name of the database, the app will connect to |
The app uses a MongoDB cluster, and assumes the following schema:
- database, named
$DATABASE_NAME
- collection, named
posts
- elements with schema:
Key Type of value _id
ObjectId
content
string
views
int
- elements with schema:
- collection, named
The "production" app
(the one that runs on https://notifai-task.herokuapp.com
)
uses database called notidai-task-db
and has a dedicated database user,
called app
, that has access only to that database.
There is also a database, created for testing,
named notifai-task-db-test
, and a user, called tester
,
that has access only to notifai-task-db-test
.
If you want, to deploy the app yourself:
-
You can use the following
MONGODB_URI
:mongodb+srv://tester:[email protected]/notifai-task-db-test?retryWrites=true&w=majority
Your app have access to the test database
notifai-task-db-test
, you will then need to setDATABASE_NAME
tonotifai-task-db-test
. -
Or you can create your own MongoDB cluster and obtain your own link
Authentication is done in the fallowing way:
- the client provides a password in a request to a dedicated
/login
endpoint. - If the password is correct, the response contains an access token (JSON Web Token), that the client can then send in requests, to authenticate itself.
- The token expires after a certain amout of time.
The posts are identified by an id, that is part of the endpint.
Since, the API is supposed to be used by other app, I decided, that all data and information will be passed through JSON, in the body of the request or response. That includes error messages and password.
One exception is the access token, which will be passed in a header
x-access-tokens
. The reasons for that are:
- This is the way It was done in a youtube tutorial,
- The token will be passed along with other data and I don't want to mix the two.
The reason why do not pass the password with any of the standard methods, is that all of the methods I've seen either are too complicated or involve a username and there are no users in this scenario.
You can also check out this API on SwaggerHub: https://app.swaggerhub.com/apis/JankaGramofonomanka/notifai-task-api/1.0.0
URL: https://notifai-task.herokuapp.com/login
Note: If you click on this URL, then "login" will be interpreted as an id
of a post, since the method will be GET
, which is not allowed here.
Allowed methods: POST
.
Methods:
-
POST
Summary: Returns an access token, if request contains the correct password
Request Body (required):
- format: JSON
- schema: JSONPassword
Responses:
-
200
- The password is correctContent:
- format: JSON
- schema: JSONToken
-
401
- Could not VerifyContent:
- format: JSON
- schema: JSONMessage
URL: https://notifai-task.herokuapp.com/create
Note: If you click on this URL, then "create" will be interpreted as an id
of a post, since the method will be GET
, which is not allowed here.
Allowed methods: POST
.
Methods:
-
POST
Summary: Creates a post and returns it's id.
Headers:
- (required) AccessTokenHeader
Request Body (required):
- format: JSON
- schema: JSONPost
Responses:
-
201
- The post has been createdContent:
- format: JSON
- schema: JSONPostId
-
401
- Unauthorized
URL (example): https://notifai-task.herokuapp.com/60a53e22829684a3b51c39b5
Note: the above URL is just an example, this particural postId
doesn't have to exist.
Allowed methods: GET
, PUT
, DELETE
.
Path parameters:
postId
- description: Id of the post
- schema: PostIdSchema
Methods:
-
GET
Summary: Returns the content of the post and the number of its views
Responses:
-
200
- Content of the post and number of it's viewsContent:
- format: JSON
- schema: PostWithViews
-
404
- PostNotFound
-
-
PUT
Summary: Overwrites the post and sets the view counter to 0
Headers:
- (required) AccessTokenHeader
Request Body (required):
- format: JSON
- schema: JSONPost
Responses:
-
200
- The post has been updatedContent:
- format: JSON
- schema: JSONMessage
-
404
- PostNotFound -
401
- Unauthorized
-
DELETE
Summary: Deletes the post
Headers:
- (required) AccessTokenHeader
Responses:
-
200
- The post has been deletedContent:
- format: JSON
- schema: JSONMessage
-
404
- PostNotFound -
401
- Unauthorized
- description: Post does not exist.
- content:
- format: JSON
- schema: JSONMessage
- description: Access token is missing or invalid.
- content:
- format: JSON
- schema: JSONMessage
- description: An access token, containing an encoded expiration date
- header:
x-access-tokens
- schema: AccessToken
- description: Id of a post
- type:
string
- format: a 24-digit hexadecimal number
- example:
"a213cdaf3453bbfcf44423fa"
- description: Content of a post
- type:
string
- format: A string of length between 1 and 160
- example:
"Today I ate 6 hamburgers."
- description: An access token, containing an encoded expiration date
- type:
string
- example:
"t0T4l1y.VaL1D.T0k3n"
-
description: Content of a post an the number of it's views
-
type:
json
-
fields:
-
"content"
- schema: PostContent
-
"views"
- type:
int
- type:
-
-
example:
{ "content": "Today I ate 6 hamburgers.", "views": 123456 }
-
description: Content of a post
-
type:
json
-
fields:
"content"
- schema: PostContent
-
example:
{"content": "Today I ate 6 hamburgers."}
-
description: A password to obtain the access token
-
type:
json
-
fields
"password"
- type:
string
- type:
-
example:
{"password": "drowssap"}
-
description: A message about an error or other event
-
type:
json
-
fields
"message"
- type:
string
- type:
-
example:
{"message": "Aliens attacked our database."}
-
description: An access token, containing an encoded expiration date
-
type:
json
-
fields:
"token"
- schema: AccessToken
-
example:
{"token": "t0T4l1y.VaL1D.T0k3n"}
-
description: Id of a post
-
type:
json
-
fields:
"id"
- schema: PostIdSchema
-
example:
{"id": "a213cdaf3453bbfcf44423fa"}
Lookup ./testing/README.md
to read about testing.
Note: there are to requirements.txt
files:
./requirements.txt
- requirements to run the app./testing/requirements.txt
- requirements to run tests
Make sure to satisfy the right requirements, if you run the app or tests.