Commit 0ba14498 authored by Jakob Moser's avatar Jakob Moser
Browse files

Draft documentation

parent 305a6b4b
Loading
Loading
Loading
Loading
+139 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

Maintainer: Jakob Moser <moser@cl.uni-heidelberg.de>

[🔗 Website](https://status.fsco.li) that shows the status of several web services hosted by the Fachschaft Computerlinguistik. Consists of a JavaScript-powered HTML frontend and a PHP-powered backend which communicate using an API.

## Run locally

@@ -17,6 +18,144 @@ sudo docker compose up

The site is then available at http://localhost:8080

## Architecture

The application consists of two parts: A client-side part, written in HTML, CSS and Javascript, and a server-side part, written in PHP. They communicate using an API.

### The client side

```
.
├── 📄 index.html
├── 📁 css
│   └── 🎨 style.css
├── 📁 img
│   ├── 🖼️ dropdown.png
│   ├── 🖼️ favicon.png
│   ├── 🖼️ header.jpg
│   ├── 🖼️ logo.png
│   ├── 🖼️ news.png
│   ├── 🖼️ rocket.png
│   └── 🖼️ ticker.png
└── 📁 js
    └── 🧩 index.mjs
```

The client-side code consists mainly of `index.html` and `index.mjs`, accompanied by some CSS and images for styling. 

All these files are _static_, meaning that they are not in any way interpreted by the server, but just sent to the client (i.e. your browser) as is. This is generally nice for scenarios where load balancing is important, because static files can be cached and easily distributed, after all, there is no central database that could be a bottleneck.

Static sites can also be nicely (and freely) hosted using [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/) or [GitHub Pages](https://pages.github.com/). Several people use static sites for blogging. “But wait, isn't a blog dynamic? After all, new blog posts are added all the time.”, you might wonder, and you wouldn't really be mistkane: A blog _feels_ very dynamic, but actually only needs to be changed whenever you want to add a blog post. For the rest of the time, it is static. As long as you are comfortable with editing an HTML file (or some other kind of text file) when posting, a blog is actually a pretty static thing.

Back to the status page. “Hey now, a status page is definitely dynamic. How should this work with a static website?”, you might wonder, and you wouldn't be mistaken: With an entirely static website, it doesn't (unless you are comfortable with editing the status page manually every time there is an update).

This is why the client side here actually does not contain any data. The JavaScript program `index.mjs` makes HTTPS requests to the server side (which is very dynamic) over an API, which returns the data the program than integrates into the website for displaying in your browser.

### The API

So how do those requests look like? And how do the replies from the server look like?

A request looks like this:

`GET` https://status.fsco.li/api/v1/services

And a response like this:

```json
[
  {
    "name": "Website",
    "host": "fachschaft.cl.uni-heidelberg.de",
    "status": "up",
    "category": "public"
  },
  {
    "name": "Tickets",
    "host": "tickets.cl.uni-heidelberg.de",
    "status": "up",
    "category": "public"
  }
]
```

The response is a list of objects in the JSON format (very similary to a list of dictionaries in Python). For every service, it lists the name, the host, the status and a category that the JavaScript script will use to build the webpage that is ultimately displayed by your browser.

You might wonder if there is a more standardized way to specify how an API looks like than giving some examples in a continuous text. And you would be right, there is a way:

```
.
├── 📁 api
│   └── 📁 v1
│       ├── 📄 index.html
│       └── 📋 openapi-spec.yaml
└── 📁 lib
    └── 📁 redoc
        ├── 📄 LICENSE
        ├── 🧩 redoc.standalone.js
        └── 📄 redoc.standalone.js.LICENSE.txt
```

The file `api/v1/openapi-spec.yaml` contains a description of the API in a machine-readable format (namely the OpenAPI format). This can be rendered by various tools, e.g., the Swagger Editor or Redoc, or the GitLab-integrated viewer.

Of course, displaying them is not the only thing you can do with OpenAPI files. You could also validate check for consistency, or even automatically generate clients and servers for a given API as described in such a file.

The `api/v1/index.html` and everything in `lib/redoc` is static code that renders the OpenAPI specification for a visitor. This means you can comfortably look at the API at https://status.fsco.li/api/v1.

* [Swagger Editor](https://editor.swagger.io/)
* [Redoc](https://redocly.github.io/redoc/)

### The server side

```
.
└── 📁 api
    ├── 🔑 .htaccess
    └── 📁 v1
        ├── 🔑 .htaccess
        └── 🐘 services.php
```

<!-- TODO -->

### Docker

```
.
├── 🐋 docker-compose.yml
└── 🐋 Dockerfile
```

<!-- TODO -->

## Deployment

<!-- TODO -->

## Questions & Answers

### The PHP code doesn't look very idiomatic, does it?

You're probably right. PHP is often mixed together with HTML to form some kind of templating system where the `.php` file directly produces HTML that is sent to and displayed in the browser.

This is also how PHP is explained in many tutorials, e.g. this one:

* [PHP: Your first PHP-enabled page - Manual](https://www.php.net/manual/en/tutorial.firstpage.php)

However, nothing about PHP (the language) mandates that it has to output HTML. If you prefer to have a clear separation of concerns (server code only supplies data in machine-readable format, client code deals with presenting that to the user), you can write a “modern-style” API returning JavaScript in any language, including PHP.

One goal of this project is to show that this is possible.

### Why the convoluted directory structure for the API?

Why is the PHP code located in `/api/v1/services.php` and not simply in a file `/services.php`?

First, it is common to separate the API routes of a web application from the routes that e.g. serve the frontend, therefore `/api/`.

Second, you should version your API, e.g. using Semantic Versioning (version numbers in the format `MAJOR.MINOR.PATCH`, e.g. `1.0.0`). It is then common to add the major version number to the API path. If you make incompatible changes to your API, you increase the major version number. This allows you to easily keep the old version of the API as long as some clients still need it. Therefore `v1/`.

This is why we have chosen a more convoluted-looking directory structure instead of just placing the file at root level.

* [Semantic Versioning](https://semver.org/)

## License