# Hello World Service

Hello World Service is the reference template of a SmartGears 4 service. It exposes a few REST
methods that show what a service gets from SmartGears: the identity and the roles of the caller,
the Context of the request, the container it runs in, the methods excluded from authorization, the
errors returned to the client, a custom HTTP method, plugins and the preparation of the service in
each of its Contexts.

Every method is described in the REST API documentation (ReDoc and Swagger UI), reached from the
menu of these pages.

## Authorization

D4Science adopts [OIDC (OpenID Connect)](https://openid.net/connect) for authentication and UMA 2
(User-Managed Access) for authorization. Every request carries a
[JSON Web Token (JWT)](https://jwt.io/) access token in the `Authorization` header:

```text
Authorization: Bearer <token>
```

The token says who the caller is, in which Context the request is made and which roles the caller
has there. Instructions to obtain a token are at
<https://dev.d4science.org/how-to-access-resources>.

The paths listed under `excludes` in `application.yaml` need no token: in this service `/guest`
and everything under it, and `/excluded`, which has no method and only shows the syntax. A path
listed under `includes` needs a token even under an excluded path: an include wins over any
exclude. In this service `/guest/private` is included back.

```yaml
excludes:
  - path: /excluded
  - path: /guest
  - path: /guest/*
includes:
  - path: /guest/private
```

SmartGears excludes by itself the landing page and the dashboard (`/index.html`, `/dashboard.html`,
`/landing/`) and the documentation (`/docs/`, `/api-docs/`, `/branding/`). A plugin may say that its own path needs no token, as the greeter does
(see [Plugins](#plugins)).

## Methods

| Method | Path | Token | Result |
| --- | --- | --- | --- |
| GET | `/hello` | required | A greeting with the caller, the Context, the infrastructure and the roles of the caller |
| GET | `/details` | required | The Context, the caller and the container, as JSON |
| GET | `/auth` | required | A message, for a caller with the role `myRole` |
| GET | `/auth/member` | required | A message, for a caller with the role `Member` |
| GET | `/auth/org_member` | required | A message, for a caller with the role `OrganizationMember` |
| GET | `/guest` | none | A message |
| GET | `/guest/bad-request` | none | Always `400 Bad Request` |
| GET | `/guest/not-found` | none | Always `404 Not Found` |
| PURGE | `/guest/test-purge` | none | Always `204 No Content` |
| GET | `/guest/private` | required | A message naming the caller: a path under `/guest` that needs a token |
| GET | `/plugins/{id}?who=<name>` | as the plugin says | The greeting of the plugin `id` to `<name>` (default `world`); `404 Not Found` for an unknown `id`. `/plugins/greeter` needs no token |

The `/auth` methods are restricted with the `@AuthorizationControl` annotation of
`authorization-control-library`, which answers `403 Forbidden` to a caller without the role. The
annotation is enforced only when the project is woven with the `aspectj-maven-plugin`, which the
`pom.xml` of this template keeps commented out: without it every caller with a valid token gets the
message.

PURGE is not a standard HTTP method, so it is not in the REST API documentation, which knows only
the standard ones. It is widely used for this action, e.g. by
[Varnish](https://varnish-cache.org/docs/trunk/users-guide/purging.html). The method is declared
with the `@PURGE` annotation of the service (`jakarta.ws.rs.HttpMethod("PURGE")`).

## Plugins

A plugin is a jar, carried in the war of the service, that adds a function to the service without
changing its code. The service names the interface its plugins implement in its `application.yaml`:

```yaml
plugins: org.gcube.service.helloworld.plugin.HelloWorldPlugin
```

The interface is in [hello-world-plugin-api](https://code-repo.d4science.org/gCubeSystem/hello-world-plugin-api),
and the war carries one plugin,
[hello-world-greeter-plugin](https://code-repo.d4science.org/gCubeSystem/hello-world-greeter-plugin),
whose identifier is `greeter`:

```bash
curl 'https://<host>/hello-world-service/plugins/greeter?who=Luca'
```

The service finds its plugins with a `ServiceLoader` of `HelloWorldPlugin` and answers for each at
`/plugins/<id>`. SmartGears finds the same plugins when the service starts and, with no code of the
service:

- describes each one from the Maven packaging of its jar, at
  `/smartgears/hello-world-service/plugins`, on the landing page of the service and in the
  Information System;
- reads its configuration, `hello-world-greeter-plugin.yaml` for the greeter (`greeting: Hello`),
  and gives it to the plugin. The service gives it to every instance of the plugin it creates, and
  does not use a plugin whose configuration is missing: the greeting comes from that file;
- gives it a row in the health of the service, with the checks of the plugin (`greeter` for the
  greeter);
- counts its requests under its name in the metrics, with the label
  `plugin="hello-world-greeter-plugin"` (`plugin="none"` for the requests to the service itself).

How a plugin is written is in the documentation of
[hello-world-plugin-api](https://code-repo.d4science.org/gCubeSystem/hello-world-plugin-api/src/branch/master/documentation/index.md)
and of
[hello-world-greeter-plugin](https://code-repo.d4science.org/gCubeSystem/hello-world-greeter-plugin/src/branch/master/documentation/index.md).

## Preparation in Each Context

A service may need to prepare itself in each Context it runs in, e.g. to read or create its
configuration there. The class `GreetingPreparation`, annotated `@ContextPreparer`, does it for this
service: SmartGears calls it in each Context of the node, with the secret of that Context, and shows
the state of the service in each Context in its health. This service only notes when it was
prepared in a Context.

## Errors

An error is returned with its HTTP status and a body describing it:

```json
{
 "success": false,
 "message": "Your request is not valid",
 "result": null
}
```

The most common statuses are:

- **400 Bad Request**: the request is not valid;
- **401 Unauthorized**: the request has no token, or the token cannot be verified;
- **403 Forbidden**: the caller lacks the role the method requires;
- **404 Not Found**: the requested path or instance does not exist;
- **405 Method Not Allowed**: the HTTP method is not supported for the URL; the `Allow` header
  lists the supported ones;
- **500 Internal Server Error**: a failure of the service, to be reported in the
  [D4Science ticketing system](https://support.d4science.org) with the request, the time it was
  made and how to replicate it.

## SmartGears Methods

As any SmartGears service, its SmartGears methods are served by the SmartGears webapp of the
container under `/smartgears/hello-world-service/`, e.g. `/smartgears/hello-world-service/health`
(`503` when the service is not ready) and `/smartgears/hello-world-service/lifecycle`. They check
their callers themselves. The health has a row for each plugin and the state of the service in each
Context. The metrics are the container's, at `/smartgears/metrics`; the requests to
the service carry the label `service="hello-world-service"` and the label `plugin`: the artifactId of the
plugin whose path the request is on, or `none`. What each of them returns is in
[What a SmartGears Node Exposes](https://code-repo.d4science.org/gCubeSystem/common-smartgears/src/branch/master/documentation/smartgears-endpoints.md);
what a service declares to SmartGears, plugins included, is in
[What a Service Declares to SmartGears](https://code-repo.d4science.org/gCubeSystem/common-smartgears/src/branch/master/documentation/writing-a-service.md).

## Postman Collection

The Postman collection of the service is at
`<service>/api-docs/postman/hello-world-service.postman_collection.json`, with an example
environment for `/gcube/devsec/devVRE` at
`<service>/api-docs/postman/hello-world-service-for-devvre.postman_environment.json`. The
environment is completed with the D4Science username and password of the user, to obtain the token.

## Service Discovery in the Information System

SmartGears publishes the service in the Information System as an EService, identified by its
SoftwareFacet. It is found with the following query, sent to the Resource Registry:

```json
{
 "type": "EService",
 "consistsOf": [
  {
   "type": "IsIdentifiedBy",
   "target": {
    "type": "SoftwareFacet",
    "group": "org.gcube.service",
    "name": "hello-world-service"
   }
  }
 ]
}
```

## Maven Coordinates

```xml
<groupId>org.gcube.service</groupId>
<artifactId>hello-world-service</artifactId>
```

## Writing These Pages

This service is the reference example of the documentation of a gCube service too: its landing
page, in `documentation/landing/`, and these pages. [Writing the Documentation](writing-documentation.md)
shows every construct the documentation site supports, with the source that produces it.

```eval_rst
.. toctree::
   :hidden:
   :maxdepth: 2

   writing-documentation
```
