Costs to Expect API v2.00.0, well v2.00.1

Yesterday was release day; I released v2.00.0 of the Costs to Expect API and pushed two minor updates to the Costs to Expect Website and Web app.

Other than two minor issues, the releases went better than I expected. I did release a small hotfix that fixes one of the problems as it was publically visible, the other will get resolved in v2.01.0.

I have two Postman monitors that run daily; I also run these regularly during development to try and ensure I don’t break anything. Collection one contains all the HTTP requests the Website makes; collection two is more thorough and has HTTP requests for nearly all API endpoints. The two collections include around 1200 tests, these test the HEADERS, returned status codes and the response body. There were no tests for the issues; they slipped through the net. I have added a ticket to my tracker to add tests to catch any possible regressions.

My Postman collections are far from perfect; they give me some confidence, but as is evident based on the v2.00.1 release, there are still gaps.

I’m going to work on improving the monitors, for the last six months, anytime a feature gets added to the API, a test gets added to the relevant collection. Testing is going to be especially important when I start developing the app in a few weeks.

Version 2.00.0 on the way

The initial development work for v2.00.0 of the Costs to Expect API is almost complete. I’m just one dev session away from all 1200 Postman tests passing.

I used the word initial, the v2.00.0 branch works; however, the two core features are not going to be complete until a couple/few .01 releases after v2.00.0. The base v2 version is about getting the database ready and ensuring all the migrations are valid; it is a significant change to the v1 database.

Permitted users are pretty much complete, the API will be missing the management of users, but that will quickly appear in .01 release.

Multiple item types, this is the big one.

As mentioned above, the database work will be complete; I should be able to write simple migration files for all additional releases without affecting existing data. The code is a little bit of a clutz; I’m merely joining to the only known item type sub table.

Updating all queries with a join to the item_type_allocated_expense table works; however, the code isn’t dynamic. When additional item types get added, creating, deleting, sorting and searching will all fail.

Once I am happy with the initial v2.00.0 release, I will add permitted users management and then work out how I am going to refactor the code to support dynamic item types. I have several ideas; however, I need to come up with something scalable and going forward will work for what I have planned for v2, v3 and beyond.

I had planned the first (private) release of the Costs to Expect app to be in late September, given the additional work, I suspect it will now get bumped into October.

We should still have something ready for public consumption before the end of the year. We are experiencing a minor bump in the road; these issues aren’t anything I wasn’t going to have to work out anyway, I have to solve some interesting problems sooner rather than later.

Costs to Expect API, v1.24 -> v2.00

Before I start developing the Costs to Expect app, I need to enhance the Costs to Expect API. Two significant features are going to be in the next version of the API, permitted users and multiple items types.

Permitted users

The Costs to Expect API supports authenticated users; however, the assumption is all authenticated users have the same data access. This system works at the moment because there are only two users; this works at the moment as there are only two users. The app needs to support multiple users with their own private data, so I’m going through the app and adding the necessary user links.

Multiple item types

The `item` table is set up for child expenses; that was all I needed for the initial development of the API. Looking forward, the API needs to support more complex item types. In the next release, I’m going to add support for multiple items types with a long term goal being support for custom item types.

The item type will need to be selected when you create a resource type. If you are tracking expenses you will choose `expense item type`, for budgeting you would choose `budget expense type`, and for a list, you would select `list item type`.

Custom item types will be coming; at this time, I can’t confirm when. I need to develop the budgeting and forecasting system; after that, I will be able to give a rough timeline.

Version 2.00

The features above are significant, far more significant than any additions to the API since its release in 2018. I feel that these additions are enough to justify a v2.00 release. 

A bump in the major version means I’m not going to support upgrades from v1.24 to v2.00. Upgrading from v1 to v2, will be possible. To upgrade you will need to export and import your existing data into a new instance of the API. I suspect there will be a join/relationship table between `items` and their data. Until v2.00 of the API is out, I am unable to confirm the exact setup; it is still in development.

Custom item types are unlikely to be supported in the v2.00 branch, I suspect, they will be the notable feature for v3.00. Unlike the jump from v1 to v2, I can guarantee there will be an upgrade path from v2 to v3, the existence of the app and website (Costs to Expect service) will require it.

PATCH support…finally.

I added PATCH support to the Costs to Expect API in November. At the time I did the minimum, I only added PATCH support for items as that was the only data we needed to edit.

In March, I reviewed the PATCH code, making a few minor alterations.

It is now time to add PATCH support to the rest of the API. PATCH support will be added for resource types, resources, categories, subcategories and category assignments for items.

When I reviewed the PATCH code in March, I was looking at a single instance. This time I need to implement PATCH support across multiple routes; we will see how many changes I make in attempting to make the code DRY.

I have six tickets in my tracker, one for each route plus one additional chore for minor refactoring. If everything goes well, I should have a release ready in a few days, and I shouldn’t have created any extra refactoring chores.

Slight delay to phase two

I had planned to start developing the Costs to Expect service during the summer, as always, there be a slight delay. We decided that rather than steam ahead with new development, it made sense to deal with some of the technical debt.

Looking at the planner, I’ve got somewhere between two and four weeks of development to complete depending on how much debt we decide to pay back.

As it stands today, our release plans are as below;

Costs to Expect API

  • v1.21.0 – Similar to the latest release, prep work and refactoring.
  • v1.22.0 – PATCH support for categories, subcategories, resource types and resources.
  • v1.23.0 – Summaries for categories, subcategories, resource types and resources
  • v1.24.0 – Add support for permitted users.

Costs to Expect website

  • v1.10.0 – General housekeeping and prep.
  • v1.11.0 – Authentication

Phase two of the Costs to Expect service should begin after the above is complete. Phase two is a migration project; the functionality that exists in the web-app needs to be migrated to the website. My Wife will then be able to use the website full time, and the web-app can be taken offline.

PHPStorm, Docker and Xdebug

I use Docker for development; on the whole, I love it; however, getting a couple of things set up proved a little challenging, namely debugging from PHPStorm with Xdebug.

Eventually, I will update my Docker quick start project on GitHub, however for now, here are some basic instructions.

We need a couple of arguments in our .env file;

 WITH_XDEBUG=true
PHP_IDE_CONFIG=serverName=[name-of-server-in-IDE]
XDEBUG_CONFIG=remote_host=host.docker.internal

Next, we update the Dockerfile

ARG WITH_XDEBUG=false

RUN if [ $WITH_XDEBUG = "true" ] ; then \
pecl install xdebug; \
docker-php-ext-enable xdebug; \
echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
echo "display_startup_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
echo "display_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini; \
fi ;

Finally, on the Docker side, we need to update our docker-compose file.

 services:
yourservice:
build:
args:
- WITH_XDEBUG=${WITH_XDEBUG}
env_file: .env

Set up your server, making sure to choose your debugger, Xdebug in this case. Settings -> Languages & Frameworks -> PHP -> Servers. The name of the server should match the name you set in the .env file.

Set the debug port and enable “can accept external connections”, PHPStorm, settings -> Languages & Frameworks -> PHP -> Debug, the port defaults to 9000.

Add a run/debug configuration (Run -> Edit configurations), select your server and optionally set an IDE key. To ensure everything is set correctly, you can use the validate option to check your configuration.

Start listening, add a breakpoint and away you go, you can now debug an app running in Docker.

Summer of fun

If I maintain the same development pace as the last eight weeks, I’m due to have a “Summer of fun”.

I’m two weeks away, one development iteration from a point in which I’ll be comfortable letting the Costs to Expect API and website run throughout the summer untouched.

They won’t be untouched; both the website and API are under active development; I’ll focus my energy on building the service, not the public website.

Dependant on your experience, as a developer, you don’t typically get to spend too much time working on new projects solving problems entirely new to you. Mid-way through July, that is me, I’m planning on locking myself in my office and getting down and dirty with my IDE, whiteboard, pen and paper.

My wife and children have told me that they have a very different idea on what a “Summer of fun” is; I’m guessing it is far less coding than my plan.

API endpoints, filtering, sorting, searching, limiting and summarising

The Costs to Expect API is developing slowly; features get added as I need them, v1.15.0 is an exciting release, it will be the first time an endpoint in the API can be filtered, sorted, limited, searched and summarised.

I’ve written previously about summarising collections, with the release of search in v1.15.0 it makes send to describe all options supported by the items (/v1/resource-types/[resource-type]/resources/[resource]/items) collection on the Costs to Expect API.

By default, the items collection returns all child expenses in reverse chronological order, ‘all’ and ‘reverse chronological’ are sensible defaults; however, the API is limited if the collection always returns everything, you need to be able to filter, sort, limit, search and summarise.

The Costs to Expect API supports filtering, sorting, limiting and searching via parameters appended to the URI, collections are summarised by prepending /summary/ to the URI. Summary endpoints support the same filtering and searching options as their companion collections, limiting and sorting don’t make any sense in the context of a summary.

A URI can quickly become unreadable when multiple GET parameters are assigned, to attempt and improve readability I have grouped sorting and searching.

The OPTIONS requests for the Costs to Expect API detail all the supported GET parameters, in addition to giving an overview of each parameter, the OPTIONS requests list which fields and sortable and searchable. The sort and search parameters both allow multiple conditions.

Limiting a collection is handled as expected, there is an offset parameter to define the start record and a limit parameter to define the number of records requested.

Filtering a collection is handled via individual parameters, filtering is more common than searching and in my opinion needs to be the most verbose, when reviewing a URI the filtering parameters should be more visible.

This solution won’t work for everyone; however, if you need to support filtering, searching, sorting, limiting and summarising, I think it provides an excellent level or readability while still being practical.

Slowly developing Costs to Expect

I’m developing Costs to Expect in a slightly different manner to any of my previous large personal projects. The process is slightly different for two reasons, firstly, the design, secondly, I’m deliberately developing at a slower, more iterative pace.

Design.

There are two parts to Costs to Expect, the Open Source API and the website, the website will include the secret sauce for the service.

The API has not been explicitly written for the Costs to Expect website; the intention has always been to use it for separate projects and idealy give back to the community, hence being Open Source. So far, I have one other project that uses the API, and I have plans for another rattling around my head. I’m confident that eventually, tomorrow maybe, I will add a feature to the API specifically for the website. I intend to try and ensure features are only added to the API if they make sense in the context of the API.

Slow, iterative development.

I released the API during the summer and developed a simple app to allow my wife to enter expenses for our children; the API is not anywhere near complete, I am continually fleshing out the features priotising the features I need to develop the website, the latest example is sorting. The web app my wife uses does not require sorting, the public Costs to Expect website does; that is why I’m adding it now.

There are three initial phases of the development of the website; once all three are complete, the real project begins.

Phase 1: The website consumes the API and shows the current expenses for our children in an engaging way for public consumption.
Phase 2: My Wife is able to transition from using the web app I developed in the summer; she should be able to do the expenses management for our children using the website.
Phase 3: I develop the forecasting and budgeting systems and start opening up the website to a restricted number of test users.

I’m very much in Phase 1. I envision I have at least another four weeks of development before I can progress to Phase 2.

Phase 2 isn’t complicated; I need to ensure I make the correct decisions, I need to work out my authentication, probably oAuth, how I’m going to handle users, groups and then develop the management pages.

Phase 3 will be when the fun begins and the part I’m most looking forward to reaching. Phases 2 and 3 require time; I mostly know what is needed; I need to design and then code the systems.

The majority of my year off will be in Phase 3, I know what I need to end up with, however, I’m currently not quite sure how I’m going to get there.

For each Phase, I’m developing very slowly; the visual design is mostly solved thanks to a highly skilled designer I employed late last year, I mostly only need to think about what I need and how to develop it.

As a single developer with limited development time and resource, I can’t afford to waste any of my development time. I’m prototyping every feature and then slowly developing them, as an example, the website won’t be connecting to the API until at least v1.04.0, up until then I’ll be working on the responsive layout, building the view components I require and experimenting with the UX.

API Summary routes

In a previous blog post, I outlined my solution to summary routes, in short, every route in my API will have a matching summary route, the summary route is simply the route with a summary/ prefix.

If the GET endpoint of a route supports parameters the summary route should support the same parameters, in my experience, it will need additional parameters; as always, best shown with an example.

The summary route lives at summary/resource-types/[resource-type]/resources/[resource]/items, the GET endpoint has eight parameters, below I’ll show the expected output for each parameter.

In my API I have the following route /resource-types/[resource-type]/resources/[resource]/items. The GET endpoint returns a collection of the items assigned to the resource; it has four parameters for filtering, year, month, category and subcategory.

No parameters | Total sum of items
years | Summary for each year
year | Summary for the requested year
months | Summary for each month
month | Summary for the requested month
categories | Summary for each category
category | Summary for the requested category
subcategories | Summary for each subcategory
subcategory | Summary for the requested subcategory

So far I’ve not come across any negatives to this structure, yes, there are numerous parameters for the GET endpoint, I don’t consider that an issue, I’d rather have fewer routes than fewer GET parameters.