Skip to content

Commit

Permalink
Added access header visual to frontend example
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelgfeller committed Apr 14, 2024
1 parent 7597ba0 commit c419457
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
run: composer update --no-ansi --no-interaction --no-progress

- name: Execute database migrations
run: composer migrate-prod
run: composer migrate:prod

- name: Show test db tables
run: mysql -uroot -proot -D ${{ matrix.test-database }} -e "SHOW TABLES;"
Expand Down
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<h1>Slim <img src="https://i.imgur.com/YzDYQ0V.png" width="60px" alt="API"> starter</h1>

[![Latest Version on Packagist](https://img.shields.io/github/release/samuelgfeller/slim-api-starter.svg)](https://packagist.org/packages/slim-api-starter)
[![Latest Version on Packagist](https://img.shields.io/github/release/samuelgfeller/slim-api-starter.svg)](https://packagist.org/packages/samuelgfeller/slim-api-starter)
[![Code Coverage](https://scrutinizer-ci.com/g/samuelgfeller/slim-api-starter/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/samuelgfeller/slim-api-starter/?branch=master)
[![Build Status](https://scrutinizer-ci.com/g/samuelgfeller/slim-api-starter/badges/build.png?b=master)](https://scrutinizer-ci.com/g/samuelgfeller/slim-api-starter/build-status/master)
[![Quality Score](https://img.shields.io/scrutinizer/quality/g/samuelgfeller/slim-api-starter.svg)](https://scrutinizer-ci.com/g/samuelgfeller/slim-api-starter/?branch=master)
Expand All @@ -22,16 +22,16 @@ and features.

## Features

* [Dependency Injection](https://github.com/samuelgfeller/slim-example-project/wiki/Dependency-Injection)
* [Database migrations](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations)
* [Validation](https://github.com/samuelgfeller/slim-example-project/wiki/Validation)
* [Dependency Injection](https://github.com/samuelgfeller/slim-example-project/wiki/Dependency-Injection) - [PHP-DI](https://php-di.org/)
* [Database migrations](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations) - [Phinx](https://phinx.org/)
* [Validation](https://github.com/samuelgfeller/slim-example-project/wiki/Validation) - [cakephp/validation](https://book.cakephp.org/4/en/core-libraries/validation.html)
* [Logging](https://github.com/samuelgfeller/slim-example-project/wiki/Logging) - [Monolog](https://github.com/Seldaek/monolog)
* [Query Builder](https://github.com/samuelgfeller/slim-example-project/wiki/Repository-and-Query-Builder) - [cakephp/database](https://book.cakephp.org/5/en/orm/query-builder.html)
* [Integration testing](https://github.com/samuelgfeller/slim-example-project/wiki/Writing-Tests) - [PHPUnit](https://github.com/sebastianbergmann/phpunit/)
* [Error handling](https://github.com/samuelgfeller/slim-example-project/wiki/Error-Handling)
* [Logging](https://github.com/samuelgfeller/slim-example-project/wiki/Logging)
* [Integration testing](https://github.com/samuelgfeller/slim-example-project/wiki/Writing-Tests)
* [Query Builder](https://github.com/samuelgfeller/slim-example-project/wiki/Repository-and-Query-Builder)
* [GitHub Actions](https://github.com/samuelgfeller/slim-example-project/wiki/GitHub-Actions)
* [Coding standards fixer](https://github.com/samuelgfeller/slim-example-project/wiki/Coding-Standards-Fixer)
* [PHPStan static code analysis](https://github.com/samuelgfeller/slim-example-project/wiki/PHPStan-Static-Code-Analysis)
* [GitHub Actions](https://github.com/samuelgfeller/slim-example-project/wiki/GitHub-Actions) - [Scrutinizer](https://scrutinizer-ci.com/)
* [Coding standards fixer](https://github.com/samuelgfeller/slim-example-project/wiki/Coding-Standards-Fixer) - [PHP CS Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer)
* [Static code analysis](https://github.com/samuelgfeller/slim-example-project/wiki/PHPStan-Static-Code-Analysis) - [PHPStan](https://github.com/phpstan/phpstan)


## Requirements
Expand All @@ -48,12 +48,12 @@ composer create-project samuelgfeller/slim-api-starter [project-name]
```
This will create a new directory with the specified name and install all
necessary dependencies.

#### 2. Set up the database
Open the project and rename the file `config/env/env.example.php` to `config/env/env.php`
and add the local database credentials.

Then, create the database on the server and update the `config/env/env.dev.php`
Then, create the database for the project and update the `config/env/env.dev.php`
file with the name of the database, like this:
```php
$settings['db']['database'] = 'my_dev_database_name';
Expand All @@ -73,7 +73,7 @@ composer migrate
```

#### 4. Insert demo data
You can install four demo users into the database to test the API response by
Four demo users can be inserted into the database to test the API response by
running the following command:

```bash
Expand All @@ -83,10 +83,14 @@ composer seed
#### 5. Update GitHub workflows

To run the project's tests automatically when pushing, update the
`.github/workflows/develop.yml` file.
Replace the matrix value "test-database" `slim_api_starter_test` with the name of
your test database as you specified in `config/env/env.test.php`.
If you are not using Scrutinizer, remove the "Scrutinizer Scan" step from the workflow.
`.github/workflows/build.yml` file.
Replace the matrix value "test-database" with the name of
your test database as specified in `config/env/env.test.php`.

If you don't plan on using Scrutinizer, remove the `.scrutinizer` file at the root of the project,
otherwise you can follow this
[guide](https://github.com/samuelgfeller/slim-example-project/wiki/How-to-set-up-Scrutinizer)
on how to set it up.

#### Done!
That's it! Your project should now be fully set up and ready to use.
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "samuelgfeller/slim-api-starter",
"description": "Example project with the slim micro-framework",
"description": "API starter template using Slim micro-framework",
"type": "project",
"license": "MIT",
"require": {
Expand Down Expand Up @@ -49,9 +49,9 @@
"phinx-migrations generate --overwrite -c config/env/env.phinx.php --ansi",
"@schema:generate"
],
"migrate-prod": "vendor/bin/phinx migrate -c config/env/env.phinx.php --ansi -vvv",
"migrate:prod": "vendor/bin/phinx migrate -c config/env/env.phinx.php --ansi -vvv",
"migrate": [
"@migrate-prod",
"@migrate:prod",
"@schema:generate"
],
"schema:generate": [
Expand Down
2 changes: 1 addition & 1 deletion config/env/env.dev.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// Set false to show production error pages
$settings['dev'] = true;

// For the that the error is not caught by custom error handler (below)
// For the case where the error is not caught by custom error handler (below)
ini_set('display_errors', $settings['dev'] ? '1' : '0');

// Display error details in browser and throw ErrorException for notices and warnings
Expand Down
5 changes: 3 additions & 2 deletions public/frontend/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
<h1>Frontend for Slim API Starter</h1>
<p>This frontend is an example of a separate application that communicates with the API.</p>
<p>The link to the actual frontend must be added to the <code>$settings['api']['allowed_origin']</code>
in the config files: <code class="file-name">config/env/env.dev.php</code> and <code class="file-name">config/env/env.prod.php</code>.
in the config files: <code class="blue-code">config/env/env.dev.php</code> and <code class="blue-code">config/env/env.prod.php</code>.
</p>
<p>You can test the API by clicking on the button below which will make an Ajax
GET request to retrieve the list of users
GET request to the <code class="blue-code">/users</code> route to retrieve the list of users
that are in the database.</p>
<button id="request-users-btn">GET /users</button>
<code id="access-header-output" style="display: none"></code>
<pre id="request-output" style="display: none"></pre>

<script src="script.js"></script>
Expand Down
76 changes: 54 additions & 22 deletions public/frontend/script.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Get the second segment of the url for the case that the application is not running in the root directory
// Get the second segment of the url in case the application is not running in the root directory
// (e.g. localhost/my-app) -> basePath = 'my-app'
const secondUrlSegment = window.location.pathname.split('/')[1];
// If the project is stored in the root directory, the second segment is the 'frontend' folder which means
Expand All @@ -7,37 +7,69 @@ const basePath = secondUrlSegment !== 'frontend' ? `/${secondUrlSegment}` : '';
// Replace with the correct API url
const url = basePath + '/users';
document.getElementById('request-users-btn').addEventListener('click', () => {
const outputContainer = document.getElementById('request-output');
// Output container is hidden by default, remove inline display: none property
outputContainer.style.display = null;

// Make Ajax request to fetch users
fetch(url, {method: 'GET', headers: {"Content-type": "application/json"}})
.then(async response => {
const outputContainer = document.getElementById('request-output');
// Output container is hidden by default, remove inline display: none property
outputContainer.style.display = null;
// Add success class to output container by default
outputContainer.className = 'success';

// Add red line border output if response is not between 200 and 299
// Display the Access-Control-Allow-Origin header value above the output container
displayAccessControlAllowOriginHeader(response);

// Parse the JSON response
let jsonResponse;
try {
jsonResponse = await response.json();
} catch (error) {
outputContainer.className = 'error';
outputContainer.innerHTML = `Unable to parse JSON response. Make sure the response is valid JSON.`;
return;
}

// Display the JSON response in the output container
outputContainer.innerHTML = prettyPrintJson(jsonResponse);

if (!response.ok) {
// Add red line border output if response is not between 200 and 299
outputContainer.className = 'error';
console.log(response.status)

if (response.status === 404) {
outputContainer.innerHTML = `Invalid API url: ${url}`;
return;
}
outputContainer.innerHTML = `Error: ${response.status} ${response.statusText}`;
return;
}

// Parse the JSON response
const jsonResponse = await response.json();
// Pretty print the JSON response
const prettyJson = JSON.stringify(jsonResponse, null, 2);
// Display the JSON response in the output container
outputContainer.innerHTML = prettyJson
// Replace newlines with <br> and remove \r, \" and \\
.replace(/\\n/g, '<br>')
.replace(/\\r/g, '')
.replace(/\\"/g, '\"')
.replace(/\\\\/g, '\\');
});
});
// Add success class to output container by default
outputContainer.className = 'success';
}).catch(exception => {
outputContainer.className = 'error';
outputContainer.innerHTML = exception.message;
});
});

function prettyPrintJson(jsonResponse) {
// Pretty print the JSON response
return JSON.stringify(jsonResponse, null, 2)
// Replace newlines with <br> and remove \r, \" and \\
.replace(/\\n/g, '<br>')
.replace(/\\r/g, '')
.replace(/\\"/g, '\"')
.replace(/\\\\/g, '\\');
}

function displayAccessControlAllowOriginHeader(response) {
// Add the Access-Control-Allow-Origin header value as the first line in the output container
const accessHeaderOutput = document.querySelector('#access-header-output');
const originHeader = response.headers.get('Access-Control-Allow-Origin');
if (originHeader) {
accessHeaderOutput.innerHTML = `Access-Control-Allow-Origin: ${originHeader}`;
accessHeaderOutput.classList.remove('no-header');
} else {
accessHeaderOutput.innerHTML = 'Access-Control-Allow-Origin header not set';
accessHeaderOutput.classList.add('no-header');
}
accessHeaderOutput.style.display = null;
}
13 changes: 9 additions & 4 deletions public/frontend/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ code {
padding: 2px;
}

code.file-name {
code.blue-code {
color: #02155e;
background-color: #f1f1f1;
padding: 2px;
}

pre {
Expand All @@ -30,11 +28,18 @@ pre {

#request-users-btn {
margin-top: 30px;
margin-bottom: 20px;
cursor: pointer;
}

#access-header-output{
color: #008fa2;
}
#access-header-output.no-header{
color: red;
}

#request-output {
margin-top: 40px;
border-radius: 20px;
padding: 30px;
background: #f1f1f1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use Phinx\Db\Adapter\MysqlAdapter;

class DbChange1187610968660592e09f632 extends Phinx\Migration\AbstractMigration
class DbChange2053913810661953ba0c3e8 extends Phinx\Migration\AbstractMigration
{
public function change()
{
Expand Down Expand Up @@ -47,6 +47,7 @@ public function change()
->addColumn('updated_at', 'datetime', [
'null' => true,
'default' => null,
'update' => 'CURRENT_TIMESTAMP',
'after' => 'email',
])
->addColumn('created_at', 'datetime', [
Expand Down
2 changes: 1 addition & 1 deletion resources/schema/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ CREATE TABLE `user` (
`created_at` datetime DEFAULT current_timestamp(),
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;

0 comments on commit c419457

Please sign in to comment.