Skip to content

Commit

Permalink
Merge pull request #154 from deanblackborough/v2.03.0
Browse files Browse the repository at this point in the history
v2.03.0 and v2.04.0
  • Loading branch information
deanblackborough authored Nov 11, 2019
2 parents a2c0903 + ef1b0d9 commit e2b1c7b
Show file tree
Hide file tree
Showing 159 changed files with 6,472 additions and 2,490 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ APP_HASH_SALT_ITEM=
APP_HASH_SALT_ITEM_CATEGORY=
APP_HASH_SALT_ITEM_SUBCATEGORY=
APP_HASH_SALT_ITEM_TYPE=
APP_HASH_SALT_PERMITTED_USER=

LOG_CHANNEL=stack

Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

The complete changelog for the Costs to Expect REST API, follows the format defined at https://keepachangelog.com/en/1.0.0/

## [v2.04.0] - 2019-11-xx
### Added
- We have added a GitHub callout to the top right corner of the API landing page, courtesy of https://github.com/tholman/github-corners.

### Changed
- We have updated the code to ensure the data arrays in the config files get used whenever possible; minor data arrays for parameters defined in two locations.
- We have added additional summary models.
- We have moved the item and resource type item models, now organised by namespace, not the class filename.
- We have moved the item and resource type item transformers, now organised by namespace, not the class filename.
- We have moved all the `existsToUser` methods out of the `item` models and into a `PermittedUser` model.
- We have updated the `item` and `resource type item` summary routes; they respect the chosen resource type (Allocated expenses and Simple expenses) and provide the relevant summary.

### Fixed
- We have corrected several more class names, incorrect capitalisation.

## [v2.03.0] - 2019-10-27
### Added
- We have added a new route, `item-types`, the route shows the item types supported by the API.

### Changed
- We have updated the landing page; the focus was previously on the website; the API is the backbone of the entire service; the site is ancillary.
- We have moved the summary controllers; we should use namespaces to organise the code, not filenames.
- We have moved the summary transformers; we should use namespaces to organise the code, not filenames.
- We have started to move the summary models; we should use namespaces to organise the code, not filenames.
- We have merged the authorised and general API routes section, the README details the API routes and the API summary routes in two tables.
- We have moved some configuration files. We thought it was odd how some were outside of folders; additionally, config files should only be in folders if there can be multiple files for the 'section'.
- We have moved localisation files to match their config partners.
- We have updated the allowed values for the `year` GET parameter; we derive the values from the data; the limit for Jack should be 2013 to 2019, for Niall te limit should be 2019.
- We have updated the GET parameter validator; supplied values validated against values defined in the OPTIONS request.

### Fixed
- We have corrected the category summary routes in the README.
- We have corrected the name of a few transformers, incorrect capitalisation.
- We have corrected the name of a few controllers, incorrect capitalisation.
- We have set the salt for the item type hasher.
- For uncaught exceptions, we return the trace when the API is in development mode.
- We have updated the code to generate conditional GET parameters; the item type defines which parameters exist.

## [v2.02.0] - 2019-10-07
### Added
- We have updated the create resource type route. It is now possible to set the item type that you want to use. There are two expense types, "allocated expense" and "simple expense". An allocated expense allows you to allocated a percentage of the total cost; a simple expense only has a total, no allocation rate.
Expand Down
120 changes: 51 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,12 @@

## Overview

What does it cost to raise a child in the UK?
Costs to Expect is a service which focuses on tracking and forecasting expenses.
The Costs to Expect API is the backbone of the service and is not going to be
limited to expenses; however, we figured that is was an excellent place to start.

[Costs to Expect](https://www.costs-to-expect.com) is a long-term personal project, my wife and I are tracking
the expenses to raise our children to, adulthood, 18.

### Why?

There are two core reasons as to why we are doing this. I love data, and over the last twenty years,
it appears to have become accepted knowledge that it costs £250k to raise a child in the UK.

If you think about the number, it becomes apparent quickly that it can't be right, on average over
£10k a year?

This API will show the costs to raise our children; obviously, every family is different, these costs only
relate to our family, more details will appear on [Costs to Expect](https://www.costs-to-expect.com) as development
on the site continues.

## The API

This Laravel app is the RESTful API for the [Costs to Expect](https://www.costs-to-expect.com) service,
the API will be consumed by the [Costs to Expect](https://www.costs-to-expect.com) website and the iOS app which
I'm creating to assist my wife with data input.
A small part of the service is tracking the costs to raise a child in the UK,
more detail can be found at [Costs to Expect](https://www.costs-to-expect.com).

## Set up

Expand Down Expand Up @@ -61,7 +45,7 @@ you will also need to set `MAIL_FROM_ADDRESS` and `MAIL_TO_ADDRESS`. You may nee

## Responses

* Collections will return an array and 200.
* Collections will return an array and a 200.
* Items will return a single object and a 200.
* Successful POST requests will return a single object and a 201.
* Successful PATCH requests will return 204.
Expand All @@ -71,7 +55,8 @@ case of a validation error, 422, the fields array will contain the validation er

## Headers

Response will include multiple headers, the table details the purpose behind each header.
Responses will include multiple headers, the table details the purpose behind some of the
custom headers.

| Header | Purpose |
| :--- | :--- |
Expand All @@ -87,52 +72,89 @@ Response will include multiple headers, the table details the purpose behind eac
| X-Search | Search options applied to request after validation |
| X-Parameters | Request parameters applied to request after validation |

## Data routes
## Routes

Access to a route will be limited based upon your permitted resource types. When you
create a resource type you have full access to everything below, additionally, the same
is true if you are assigned to a resource type.

| HTTP Verb(s) | Route |
| :--- | :--- |
| GET/HEAD | v2/ |
| OPTIONS | v2/ |
| POST | v2/auth/login |
| POST | v2/auth/register (Removed in production) |
| POST | v2/auth/register |
| GET/HEAD | v2/auth/user |
| GET/HEAD | v2/changelog |
| OPTIONS | v2/changelog |
| GET/HEAD | v2/item-types |
| OPTIONS | v2/item-types |
| GET/HEAD | v2/item-types/{item_type_id} |
| OPTIONS | v2/item-types/{item_type_id} |
| GET/HEAD | v2/resource-types |
| OPTIONS | v2/resource-types |
| POST | v2/resource-types |
| GET/HEAD | v2/resource-types/{resource_type_id} |
| OPTIONS | v2/resource-types/{resource_type_id} |
| PATCH | v2/resource-types/{resource_type_id} |
| DELETE | v2/resource-types/{resource_type_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/categories |
| OPTIONS | v2/resource-types/{resource_type_id}/categories |
| POST | v2/resource-types/{resource_type_id}/categories |
| PATCH | v2/resource-types/{resource_type_id}/categories/{category_id} |
| DELETE | v2/resource-types/{resource_type_id}/categories/{category_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/categories/{category_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/categories/{category_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories |
| OPTIONS | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories |
| POST | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories |
| GET/HEAD | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories/{subcategory_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories/{subcategory_id} |
| PATCH | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories/{subcategory_id} |
| DELETE | v2/resource-types/{resource_type_id}/categories/{category_id}/subcategories/{subcategory_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/items |
| OPTIONS | v2/resource-types/{resource_type_id}/items |
| OPTIONS | v2/resource-types/{resource_type_id}/permitted-users |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources |
| OPTIONS | v2/resource-types/{resource_type_id}/resources |
| POST | v2/resource-types/{resource_type_id}/resources |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| PATCH | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| PATCH | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id} |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/sub_category |
| GET/HEAD | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory/{item_subcategory_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/subcategory/{item_subcategory_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/sub_category/{item_subcategory_id} |
| OPTIONS | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer |
| GET/HEAD | v2/request/error-log |
| OPTIONS | v2/request/error-log |
| POST | v2/request/error-log |
| GET/HEAD | v2/request/access-log |
| OPTIONS | v2/request/access-log |

## Summary routes

Eventually there will be a summary route for every API GET endpoint, until that point, the summary routes
are detailed below. Some use GET parameters to breakdown the data, one example being items
which allows you to provide year, month, category and subcategory. A summary route should have the same
GET parameters as the non summary route.
Eventually, there will be a summary route for every API GET endpoint. Until that point, the summary routes
that exists are detailed below. Some use GET parameters to breakdown the data, one example being
`v2/summary/resource-types/{resource_type_id}/items`. Review the OPTIONS request for each summary
route to see the supported parameters, these should largely match the non summary route.

| HTTP Verb(s) | Route |
| :--- | :--- |
Expand All @@ -150,43 +172,3 @@ GET parameters as the non summary route.
| OPTIONS | v2/summary/resource-types/{resource_type_id}/resources |
| GET/HEAD | v2/summary/resource-types/{resource_type_id}/resources/{resource_id}/items |
| OPTIONS | v2/summary/resource-types/{resource_type_id}/resources/{resource_id}/items |

## Misc routes

| HTTP Verb(s) | Route |
| :--- | :--- |
| GET/HEAD | v2/changelog |
| OPTIONS | v2/changelog |
| GET/HEAD | v2/request/error-log |
| OPTIONS | v2/request/error-log |
| POST | v2/request/error-log |
| GET/HEAD | v2/request/access-log |
| OPTIONS | v2/request/access-log |

## Private routes

These routes require authorisation.

| HTTP Verb(s) | Route |
| :--- | :--- |
| GET/HEAD | v2/auth/user |
| POST | v2/categories |
| PATCH | v2/categories/{category_id} |
| DELETE | v2/categories/{category_id} |
| POST | v2/categories/{category_id}/subcategories |
| PATCH | v2/categories/{category_id}/subcategories/{subcategory_id} |
| DELETE | v2/categories/{category_id}/subcategories/{subcategory_id} |
| POST | v2/resource-types |
| PATCH | v2/resource-types/{resource_type_id} |
| DELETE | v2/resource-types/{resource_type_id} |
| POST | v2/resource-types/{resource_type_id}/resources |
| PATCH | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id} |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items |
| PATCH | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id} |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id} |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/sub_category |
| DELETE | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/category/{item_category_id}/sub_category/{item_subcategory_id} |
| POST | v2/resource-types/{resource_type_id}/resources/{resource_id}/items/{item_id}/transfer |
43 changes: 12 additions & 31 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,7 @@ public function report(Exception $exception)
public function render($request, Exception $exception)
{
if ($exception instanceof AuthenticationException) {
if (App::environment() === 'local') {
return response()->json(
[
'message' => 'Unauthenticated',
'trace' => $exception->getTraceAsString()
],
403
);
} else {
return response()->json(
[
'message' => trans('responses.authentication-required')
],
403
);
}
Response::authenticationRequired();
}

$status_code = 500;
Expand All @@ -79,16 +64,10 @@ public function render($request, Exception $exception)

switch ($status_code) {
case 404:
Response::notFound();
Response::notFound($exception);
break;
case 503:
response()->json(
[
'message' => trans('responses.maintenance')
],
503
)->send();
exit;
Response::maintenance();
break;
case 500:
if (App::environment() === 'local') {
Expand Down Expand Up @@ -129,12 +108,14 @@ public function render($request, Exception $exception)
break;
}

return response()->json(
[
'message' => $message,
'trace' => $exception->getTraceAsString()
],
$status_code
);
$response = [
'message' => $message
];

if (App::environment() === 'local') {
$response['trace'] = $exception->getTraceAsString();
}

return response()->json($response, $status_code);
}
}
10 changes: 5 additions & 5 deletions app/Http/Controllers/CategoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Http\Controllers;

use App\Models\SubCategory;
use App\Models\Subcategory;
use App\Option\Delete;
use App\Option\Get;
use App\Option\Patch;
Expand Down Expand Up @@ -51,7 +51,7 @@ public function index($resource_type_id): JsonResponse
Config::get('api.category.searchable')
);

$total = (new Category())->totalCount(
$total = (new Category())->total(
(int) $resource_type_id,
$this->permitted_resource_types,
$this->include_public,
Expand Down Expand Up @@ -123,7 +123,7 @@ public function show($resource_type_id, $category_id): JsonResponse
$this->permitted_resource_types
);

$parameters = Parameters::fetch(['include-subcategories']);
$parameters = Parameters::fetch(array_keys(Config::get('api.category.parameters.item')));

$category = (new Category)->single(
(int) $resource_type_id,
Expand All @@ -139,7 +139,7 @@ public function show($resource_type_id, $category_id): JsonResponse
array_key_exists('include-subcategories', $parameters) === true &&
$parameters['include-subcategories'] === true
) {
$subcategories = (new SubCategory())->paginatedCollection(
$subcategories = (new Subcategory())->paginatedCollection(
(int) $resource_type_id,
(int) $category_id,
0,
Expand Down Expand Up @@ -313,7 +313,7 @@ public function delete(
} catch (QueryException $e) {
UtilityResponse::foreignKeyConstraintError();
} catch (Exception $e) {
UtilityResponse::notFound(trans('entities.category'));
UtilityResponse::notFound(trans('entities.category'), $e);
}
}

Expand Down
Loading

0 comments on commit e2b1c7b

Please sign in to comment.