Oinkers is a simple and secure platform for keeping track of how you spend your money. It uses the Gruvbox color scheme and aims for a minimalist UI.
Because the source code for the frontend and server of this application is so large, I have separated it into two separate branches of this repo. The code for each can be viewed in their respective branches.
Due to Apple's app security regulations I am unable to provide a native iOS executable until it gets verified on the App Store. On Android you can visit the releases tab of this repository and download the app-debug.apk
file to install it. There is also a web-based version of Oinkers that is accessible from a browser at oinkers.netlify.app.
This app is built using web technologies that compile to native machine code for iOS and Android. These include:
- Vue.js - JavaScript framework for building dynamic web applications (similar to React)
- Node.js - JavaScript runtime that allows executing of JS outside of browsers
- Vite - Frontend tooling for development and building (hot-module reload, sub-second build times to HTML, CSS, and JS)
- MySQL - Relational database server
- NestJS - Scalable and progressive Node.js framework for building backend servers, written in TypeScript
- Capacitor - Cross platform native runtime for web apps, allows easy communication with mobile APIs and maintaining only one codebase for many platforms - built by Ionic
- Prisma - Modern ORM for communicating with databases in Node.js. Supports migrations and data visualization in almost any SQL-based database.
- TailwindCSS - Utility-first CSS framework with semantic class names, giving you more control than frameworks like Bootstrap. Tailwind is simply a collection of CSS classes like
mt-4
orborder-2
orrotate-90deg
that allow you to have full control over how you want your app to look like instead of a collection of plug-and-play components like Bootstrap or Bulma.
Using Capacitor makes developing for native mobile applications easy by writing pure HTML, CSS, and JavaScript, and you can bring along your favorite frameworks
The Oinkers API runs on a web server which is hosted in Heroku, and is accessible via oinkers.herokuapp.com. It also uses a cloud hosted MySQL database, so API calls can be made from anywhere.
This section involes the proper format of requests when using the Oinkers API.
When creating, editing, or viewing transactions a proper JWT token must be supplied in the request's Authorization
header as a bearer token.
- Creating a transaction -
POST /api/transactions/
{
name: string,
amount: float,
user: {
connect: {
username: string
}
}
}
- Viewing user transactions -
GET /api/transactions/<username>
{ no body } - Editing a transaction -
PUT /api/transactions/<id>
{
name: string,
amount: float,
user: {
connect: {
username: string
}
}
}
The frontend mobile application communicates with the Oinkers API through HTTP requests, mainly with the Axios library. Most API endpoints, such as creating/editing a post or changing a user's password require that you be authorized in order to access and utilize them. Failiure to provide authorization will return HTTP 403 (Forbidden) as a status code. How can we prove that we are logged in and authorized to access an API resource? Oinkers does this by using JSON Web Tokens.
When a user logs in, they send a POST request to the proper URL (in this case, /auth/login
) and provide the credentials they would like to use. The web server then takes those credentials and compares them with the users stored in the database. If the user is not found or the user provides an incorrect password, then they are unauthorized and cannot log in. If they provide valid credentials, then the server issues a JSON Web Token that the frontend stores in the app's local storage. This token can then be used to access restricted Oinkers API endpoints by including this token in the request's HTTP headers, for example:
PUT /api/users/
Headers:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Although it may seem like gibberish to humans, a computer can easily decode it. The web server is then able to deconstruct the web token and get things like the logged in user, expiration date, hashing algorithm, etc. This way, authentication does not depend on sessions via browser cookies and can be implemented from any client.
I really enjoyed making this app and I learned alot of things along the way. In the future I plan on making a page where users can register for accounts instead of manually creating one, as well as getting it published on Google Play and the App Store!