- Create todo item
- Update todo status to todo or in progress or completed
- Dleete todo item
- List todo items (filters, pagination)
- User signup and login
- Application authorization
Docs here Client App
Currently it is developed as SPA. It should SSR along with PKCE, a demo available on feat/auth-code-pkce
git branch
docker-compose up
Access app at http://localhost:3001/ Access API documentaion at http://localhost:3000/api-docs/index.html
- ruby 3.2.2
- bundler 2.4.10
- make 3.81 (optional)
- Docker 24.0.4 (optional)
- MySQL 8.3.0 (optional)
The application can be run in your machine either using docker or manual install.
docker compose up
# or
make docker_dev
Preparing database with sample application data.
docker-compose exec -T <app service> bin/rails db:prepare
# example
docker-compose exec -T api bin/rails db:prepare
docker-compose exec -T api bin/rails db:migrate
docker-compose exec -T api bin/rails db:seed
Before proceeding further, make sure MySQL is installed. or you can use ./docker-compose.db.yml.
-
Install dependencies
# project root bundle install
-
To configure credentials you can either use
master.key
that was shared privately or you can generate a new one for development usingbin/rails credentials:edit --environment development
-
Run migrations, database seeding
bin/rails db:migrate bin/rails db:seed
-
Launch the application
bin/rails s
*Docker must be installed
bundle install
make setup_db
make serve
The API endpoint information (Swagger OpenAPI spec) can be access at http://localhost:3000/api-docs
. To generate API docs run
bin/rails rswag:specs:swaggerize
# or
make docs
The tests are written for rspec
bundle exec rspec
# or
make specs
You can either pass env variables or use rails credentials. The env variables takes highest precedence.
db:
port: 3308
host: 127.0.0.1
user: root
password: example
allowed_cors_origins: localhost:3000
-
To consume APIs, you must sign up for an account. You can either do it from Swagger or use the below curl request
curl -X 'POST' \ 'http://localhost:3001/v1/auth/signup' \ -H 'accept: */*' \ -H 'Content-Type: application/json' \ -d '{ "user": { "email": "[email protected]", "password": "password", "password_confirmation": "password", "first_name": "L", "last_name": "M" }, "client_id": "webapp_id" }'
-
You need to authorize before making requests on
tasks
resource.# You can generate a user token locally by running below script ./dev/scripts/gen_token.sh
-
Copy the access_token from the response and pass it in
Authorization
headers for subsequent requests made ontasks
resource. -
When running the front end application make sure to configure allowed origins
ALLOWED_CORS_ORIGINS
.
app/
├── controllers/
│ └── auth_controller.rb
├── adapters/ # adapters for REST API's
│ ├── controllers/
│ │ └── tasks_controller.rb
│ └── repositories/ # adatpers for datasources. In future if we want to use another ORM this is where we implement new adapter.
│ └── task_repository.rb
├── core/ # business logic
│ ├── entities/
│ │ └── task.rb
│ └── use_cases/
│ └── tasks/
│ ├── create_task.rb
│ ├── ...
│ └── list_tasks.rb
├── models/ # Rails ActiveModels. Handles database related operations only.
│ └── task.rb
├── serializers/ # presentation layer
│ └── task_serializer.rb
spec/
├── requests/ # Generates Swagger compatable schema and tests API
└── models/
Rubocop
bundle exec rubocop
The application is developed based on Hexagonal architecture. Decouples entities from rails ORM (ActiveRecord
). With this approach (lose coupling), we can add support for GraphQL in future easily.
The authentication for users is implemented using devise
gem. As this is a API only application, it needs to authorize the incoming requests from client apps to confirm resource access, this was implemented using doorkeeper
gem.
You can create a application for your client,
Doorkeeper::Application.create(name: "MyApp", redirect_uri: "urn:ietf:wg:oauth:20:oob", scopes: ["read", "write"])
The API responses are serialized before sending to client. This will ensure the resource structure is consistent across all applicable endpoints.
The entities are responsible for validating inputs and processing the inputs. The use cases are self explanatory. The use cases are equivalent to services in hexagonal architecture.
Currently the CI pipeline actions are being run using docker. But they should be configured seperately for speeding up pipeline executions.
- The authentication token is a random hex value. Currently JWT token implementations are not incorporated into the application, due to the time constraint.
- To benefit from rails validations and to avoid re-work on validation helpers, we are using
ActiveModel::Model
in entities, due to the time constraint. Which is not correct in terms of current architecture. - Using
Resource Owner Password Flow
grant type to authorize requests from client application. Which currently have some secuirty concerns but considering the application scope it really doesnt matter. PKCEwas not implemented due to time constraint
. And also maintaining UI consistency across auth server and client application is bit time consuming task. - The test cases are covered for
use cases
andrequests
. - The swagger spec is not commited to source code. The idea is to auto generate it using github actions.
- Introducing
elasticsearch
andredis
is an overkill for the current application requirements. Hence not implemented. - Logging was not implement due to time constraint
- Rate limiting was not implemented
- Currently passwords are commited in codebase, most of them are for testing purpose. They can read from
.env
later.