REST API for Spring Voice projects. Provides a single endpoint on which to build frontend applications without directly accommodating a specific backend.
- Python 3.7+
- Access to the Spring Voice application on Firebase
- Your own Firebase app for development
Continuous integration / continuous delivery is managed by a Gitlab's CI/CD. See .gitlab-ci.yml
for details.
The following are what happens in CI/CD:
-
A branch is merged into
primary
, triggering the runner. Two pipelines will be run: test and build. -
Provided all pipelines succeed, the runner will proceed to push built image to AWS ECR. This depends on a number of environment variables, which are managed by Gitlab.
-
AWS ECR is the Docker image repository. The image will be stored here with two tags:
latest
(for last pushed image), andbranch-commit_sha-job_id
. -
(Incomplete) The plan is to deploy on Kubernetes using AWS EKS. As of now (2020-12-31), the Deployment and Service YML files needed have been created and tested locally. They work on minikube.
The API has three external dependencies: an OAuth provider, a database for submissions, and a database for user tokens. At the time of writing (2020-12-31), the first is Google OAuth; the latter two are both Google Firebase. As such, the following are required:
- Google OAuth client ID *
- Google service account key **
* See Using OAuth 2.0 to Access Google APIs for instructions. Be sure that redirect_uris
and javascript_origins
include relevant domains for the API. There is a sample in this repo, sample-oauth-id.json
.
** See Google Cloud documentation for instructions. There is a sample key in this repo, sample-service-account.json
.
See environment variables on how to implement these.
- Optional, for development: Set up and activate a virtual environment, like venv or pyenv
- Install dependencies:
pip install -r dependencies.txt
- Install dev dependencies:
pip install -r dependencies-dev.txt
- Configure environment variables
There are three environment variables which govern how the app runs. The following are mandatory:
AUTH
: Protocol and config file for OAuth providerKEY
: The secret key for token creation (see PyJWT for explanation)SUBMISSION
: Protocol and config file for submissions databaseTOKEN
: Protocol and config file for token database
The following are optional, as they have default:
ENV
: Runtime environment -development
,production
, ortesting
; defaults totesting
if not setDEBUG
: Debug mode -True
orFalse
; defaults toTrue
in development, otherwiseFalse
make run AUTH=path-to-oauth-id KEY=abc123 SUBMISSION=path-to-service-account TOKEN=path-to-service-account
will start the app in development mode. path-to-oauth-id
is location of Google OAuth client ID and path-to-service-account
location of Google Cloud service account key.
Once started, you can send HTTP requests to http://localhost:5000/api/v1/<route>
using curl or a client like Postman. Note that if you've set up Firebase correctly, you are making requests to live resources.
Tests are done in unittest and are initiated by pytest. make test
will run tests in quiet mode; otherwise, pytest <options>
can be used to run your own tests.
Linting is handled by flake8
. make lint
will lint the application and tests.
Type checking is handled by mypy
. make type-check
will type check the application and tests.
make
will run tests, linting, and type checking in that order. Do this before pushing a commit to Gitlab, as the Gitlab CI will run these operations.
There are two user roles:
-
Admin user
These are users who have administrative rights to edit / manage / delete submissions through the web app. They log in throughh the application UI, which generates an
*administrative* <TokenValue>
, which is passed via headerAuthorization: Bearer <TokenValue>
to the API. -
Mobile app / "anonymous" user
This is anyone other than admin users, who are accessing the app on mobile devices. As of the time of writing (2020-07-16), it was decided that these users would not have a perpetual identity (at least for MVP). They make submissions using the mobile app, but there is nothing linking the user to the submission he just made. Future implementations might involve authentication using a token on user's device.
The API uses REST. It accepts JSON-encoded requests (Content-Type application/json
) and returns JSON-encoded responses. Responses use standard HTTP response codes. Requests use HTTP verbs / methods; allowed methods include GET
, POST
, and PUT
.
Request:
GET /api/v1/submissions
Returns:
"submissions": {
[id]: {
"allowSNS": bool,
"allowSharing": bool,
"id": str,
"isApproved": bool,
"message": str,
"name": str,
"prefecture": str
}
}
Request:
GET /api/v1/submissions/[id]
Returns:
{
[id]: {
"allowSNS": bool,
"allowSharing": bool,
"id": str,
"isApproved": bool,
"message": str,
"name": str,
"prefecture": str
}
}
Request:
POST /api/v1/submissions
Payload:
{
"allowSNS": bool,
"allowSharing": bool,
"isApproved": bool,
"message": str,
"name": str,
"prefecture": str
}
Returns:
{
[id]: {
"allowSNS": bool,
"allowSharing": bool,
"id": str,
"isApproved": bool,
"message": str,
"name": str,
"prefecture": str
}
}
Request:
PUT /api/v1/submissions/[id]
Payload:
{
"allowSNS": bool,
"allowSharing": bool,
"isApproved": bool,
"message": str,
"name": str,
"prefecture": str
}
Returns:
{
"success": "[id] updated in submissions"
}
Below is yet to be implemented and is (as of 2020-09-07) yet to be fully thought through.
Request:
Content-type: multipart/form-data
POST /api/v1/users
Payload:
{
"identifier": str
}
Return:
{
"token": <TokenValue>,
"expires": int,
"expires_in": int
}