> ## Documentation Index
> Fetch the complete documentation index at: https://developers.luccasoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Guidelines

> Design principles behind the Lucca API.

## Get Started

### Motivation

The goal of this document is to facilitate the work and minimize the effort of all API users at Lucca while protecting their investment and encouraging API adoption.

These guidelines lay down the foundation for collaboration, stability, and extensibility.

### Content

This API guideline contains:

1. General guidelines in regard to APIs building and modeling, especially public APIs.
2. Guidelines in regard to generating events from the state of API resources.
3. A Spectral ruleset that aims at helping you implement these API guidelines in your projects.

### How to read these guidelines

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/html/bcp14) \[[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)] \[[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)] when, and only when, they appear in all capitals, as shown here.

<Note>
  * Rules are numbered, and this numbering system is also referenced in the spectral ruleset.
  * Whenever there are two key words for a given rule, then the strictest is aimed at the Lucca API, and the more lenient, to private internal APIs.
  * Whenever a rule only affects the Lucca API (public), then it is prefixed with \[LUCCA API].
</Note>

### Validating your API specs

In order to validate your OpenAPI specs with the guidelines, you may:

<Steps>
  <Step title="Make sure your OpenAPI specs is v3.x.">
    The spectral ruleset only supports OAS v3.x, ideally ^3.1.x
  </Step>

  <Step title="Install stoplight/spectral">
    ```
    npm install -g @stoplight/spectral
    ```
  </Step>

  <Step title="Install Lucca API guidelines through npm">
    ```
    npm install @lucca/api-guidelines-spectral
    ```
  </Step>

  <Step title="Lint your oas file with the spectral ruleset of this project">
    ```
    spectral lint <oas-file> -r <lucca-api-guidelines-folder>/.spectral.yaml
    ```
  </Step>
</Steps>

## Lucca API building principles

### Required Qualities

Lucca initially started as a software company that developed a single app. However, due to the founder's seemingly insatiable appetite, many complementary apps were subsequently developed.

The proliferation of apps posed two significant challenges to the platform architecture:

1. Mitigate the risk of tight coupling between applications, which would make the entire system impossible to evolve and maintain.
2. Avoid duplication and redundancy by rigorously segregating responsibilities between applications and laying out a common central to manage the remaining shared components.

Consequently, the platform **MUST**:

* Offer **simplicity** thanks to a modular and unified interface for hosted applications that acts as an abstraction layer defining a shared representation of
  an enterprise objects and processes (also called “the metamodel”, which is an enterprise ontology) and the means to interact with the state of this model.
* Be **highly available** and resilient: no single component's fault should shut down the entire system (i.e., no SPOF).
* Be **extensible**: it can welcome any new application, regardless of its origin, by making integration painless. New features can be added at a very low cost.
* **Scale** well with users expansions, without degrading performance nor profitability.

Availability is considered more important than consistency. The platform embraces **eventual consistency**, while being fully aware of the potential cost
in terms of cognitive complexity for users and developers.

Simplicity through uniformity is considered more important than **performance**.

### Top-Level Principles

As a result, here are the principles behind the Lucca API design:

1. All cross-applications interactions **MUST** go through an **asynchronous**, **uniform**, **stateless**, **resource-oriented**, **extensible,** **web interface** (WOA: Web-Oriented Architecture) when available - which is the Lucca API.
   1. *Corollary 1.1.: The Lucca API **MUST** conform to the Lucca current API standard (as of now: v4).*
   2. *Corollary 1.2.: All interactions **MUST** share a common protocol (HTTP) and message format (JSON).*
   3. *Corollary 1.3.: The enterprise model (ie the namespace) **MUST** pursue **simplicity** and **universality**. In particular, the enterprise model **MUST** adopt an atomic design methodology (primitives & composites [in the Zachman framework](https://www.zachman.com/resources/zblog/item/zachman-enterprise-engineering-primitive-vs-composite-review)) and strive to adopt narrow functional boundaries (conform to the [Zachman framework](https://www.zachman.com/) interrogatives).*
   4. *Corollary 1.4.: An application **MUST** not fail if another application is down.*
   5. *Corollary 1.5.: Any event system (webhooks) **MUST** be stateless and resource-oriented.*
   6. *Corollary 1.6.: Any application **MAY** freely extend the enterprise model.*
2. The Lucca API **MUST** be **agnostic to the actual applications** providing concrete implementations for a subset of the enterprise model.
   1. *Corollary 2.1.: The Lucca API **MUST** have full control over the enterprise model (ie the namespace).*
   2. *Corollary 2.2: Third-party app integration possibilities **MUST** be strictly equal to those of first-party apps. Anything a first-party app can do in the platform, a third-party app should be able to do. From the end-user point of view, it must be indistinguishable as long as the app developer seriously invested in the integration.*
   3. *Corollary 2.3: The Lucca API **MUST** have no opinion over the actual implementation details made by applications, as long as the interface contract with the Lucca API is respected.*
3. The Lucca API **MUST** strive to become **irresistible** by investing heavily in the developer experience.
   1. *Corollary 3.1.: The Lucca API **MUST** have proper change management and offer long-term support.*
   2. *Corollary 3.2.: The documentation **MUST** be human-readable, complete, and illustrated.*
   3. *Corollary 3.3.: SDKs **SHOULD** be published to reduce the workload of developers.*

## General Rules

### \[001] **MUST** be RESTful

All APIs **MUST** be RESTful and JSON-based (charset = UTF-8). RESTful APIs tend to be less use-case specific and come with less rigid client / server coupling.

Regarding the REST constraints, all APIs **MUST** at least be at level 2 in [Richardson's maturity model](https://martinfowler.com/articles/richardsonMaturityModel.html).

Some level 3 (i.e. HATEOAS) features **MAY** be implemented, but we do not consider it a requirement. In the Lucca API, two features are implemented:

* embeddings of related resources representations through a standardized format.
* links to related resources, which may help clients predict access control as well as expected inputs.

### \[002] **SHOULD** embrace a design first approach

In a nutshell, the Design First principle means:

1. Define the API first, before coding its implementation, using a standard specification language (we highly recommend
   [OpenAPI](https://spec.openapis.org/oas/latest.html)) ;
2. Get early review feedback from peers and client developers ; and iterate from there.
3. Then, implement the API in conformance to the definition.
4. Ideally, continuous integration checks for discrepancies between the design definition and the actual implementation.

Defining APIs first outside the code aims at facilitating early review feedback and favoring:

* profound understanding of the domain and required functionality.
* generalized business entities / resources, i.e. avoidance of use case specific APIs.
* clear separation of WHAT vs. HOW concerns, i.e. abstraction from implementation aspects — APIs should be stable even if we replace
  complete service implementation including its underlying technology stack.

Moreover, defining an API with a standardized specification format also facilitates:

* having a single source of truth for the API specification; it is a crucial part of a contract between service provider and client users
* infrastructure tooling for API discovery, API GUIs, API documents, automated quality checks.

### \[003] **SHOULD** be robust

[Robustness Principle (Postel's law)](https://en.wikipedia.org/wiki/Robustness_principle)

“Be tolerant of inputs and strict on outputs”. In other words, enforce strict validation on responses, but be more lenient on requests.
Have fail-safe defaults.

The degree of leniency may be negotiated with the client through the `Prefer` HTTP header.

### \[004] **SHOULD NOT** surprise clients

[Principle of Least Surprise](https://en.wikipedia.org/wiki/Principle_of_least_astonishment)

People are part of the system. Choose interfaces that match the user’s experience, expectations, and mental models. Avoid unexpected
side-effects and black-box effects. Conform to standards and enforce consistency and uniformity.

### \[005] **SHOULD** always be explicit

Document the assumptions behind the design so that when the time comes to change it you can more easily figure out what else has to change.
Expect not only to modify and replace modules, but also to remodularize as the system and its requirements become better understood.

### \[006] **SHOULD** embrace an collaborative and iterative design process

You won't get it right the first time, so make it easy to change. Do not try to anticipate future changes, you'll mostly miss the mark.
Take time to refactor existing components whenever the system changes.

Besides, let anyone comment on the design; you need all the help you can get.

Eventually, kill rarely used components: deterioration and corruption accumulate unnoticed.

### \[007] **SHOULD** define useful resources

As a rule of thumb resources should be defined to cover 90% of all its client's use cases. A useful resource should contain as much
information as necessary, but as little as possible. A great way to support the last 10% is to allow clients to specify their needs
for more/less information by supporting filtering and embedding.

You **SHOULD** avoid excessive generality when modeling resources: if it is good for everything, then it is good for nothing.

### \[008] **MUST** secure your API

Check every operation for authenticity (who), integrity (what), and authorization (can).

### \[009] **MUST** be transparent regarding access rights

Document all access rights that may not be immediately understood ; all the more so if this affects data that could be considered sensitive.
For example: granting someone the right to create leaves for another employee may reveal this employee's work-contract dates if errors
are thrown when attempting to create leaves outside the contract date range.

## Endpoints

### \[100] **MUST** use kebab-case for paths naming

<CodeGroup>
  ```http HTTP Examples theme={null}
  GET /lucca-api/leave-requests HTTPS/1.1
  GET /lucca-api/time-entries HTTPS/1.1
  ...
  ```
</CodeGroup>

### \[101] **SHOULD** use paths that conform to resources names

Paths **SHOULD** stick to the plural form of the name of the type of resource when not a singleton resource. In practice,
when the resource is listed in a collection, then the path should be equal to the `type` of the collection representation.

<CodeGroup>
  ```http HTTP Example theme={null}
  GET /leave-requests HTTPS/2
  {
      "type": "leave-requests",
      "items": []
  }
  ```
</CodeGroup>

### \[102] **MUST** conform to HTTP methods standard semantics

Be compliant with the standardized HTTP semantics (refer to [RFC-9110](https://www.rfc-editor.org/rfc/rfc9110.html)).

<AccordionGroup>
  <Accordion title="GET requests are used to read either a single or a collection of resource(s) representation(s).">
    `GET` requests **MUST** be safe (i.e. they must not change the server state) and thus idempotent.

    `GET` request **SHOULD** be cacheable.

    `GET` requests for individual resources **SHOULD** return a 404 if the resource does not exist or it is not accessible to the authenticated user.

    `GET` requests for collection resources **MAY** return either 200 (if the collection is empty) or 404 (if the collection is missing or inaccessible).

    `GET` requests **SHOULD NOT** return a 202, and therefore should not be asynchronous.

    `GET` requests **MUST NOT** have a request body payload. Use query parameters, and in the worst case, a `POST` request. Do not use headers for this.

    `GET` requests on collection resources **SHOULD** provide sufficient filter and pagination mechanisms.
  </Accordion>

  <Accordion title="PUT requests are used to update - or create if it does not already exist - entire resources.">
    The semantic is best described as "please put the enclosed representation at the resource mentioned by the URL, replacing any existing resource".

    `PUT` requests **MUST** have an idempotent behavior.

    `PUT` requests **SHOULD NOT** usually be supported on collection resources. Otherwise, please refer to the “batch requests” part of this document.

    `PUT` requests **SHOULD** return a 201 (without a `Location` header as the resource was created on the URL targeted by the `PUT` request) whenever it translates
    to the creation of a new resource ; and a 200 whenever it updates an existing one. A 202 **MAY** be returned to indicate asynchronous processing.

    `PUT` requests **SHOULD** return the representation of the updated/created resource whenever it contains server-generated properties.

    `PUT` requests **SHOULD** be used for resource creation whenever the client has the control over the URI (and thus, usually, the identifier).

    `PUT` requests **SHOULD** support `If-Match` and `If-None-Match` headers in order to given clients a better control over concurrency and avoid lost updates.
  </Accordion>

  <Accordion title="POST requests are usually used to create single resources on a collection resource endpoint, but may also be used to execute commands on single resources endpoint.">
    In regards to collections, its semantic is best described as "please add the enclosed representation to the collection resource identified by the URL".

    For single resource endpoints, its semantic is to be understood as "please execute the given well specified request on the resource identified by the URL".

    `POST` requests do not require to be idempotent, but **MAY** be implemented in an idempotent way.

    `POST` requests **MAY** support batch creations through sending a collection (i.e. an object that list the representations of the items to create). Please refer to the
    "batch requests" part of this document to learn more.

    `POST` requests, when intended for creation and successful, **MUST** return a 201 as well as the URI of the created resource(s) in the `Location` HTTP header.

    `POST` requests, when intended for creation and successful, **SHOULD** return the newly created resource, with its `GET` representation in the response body.

    `POST` requests **MAY** return a 202 when asynchronous, but **SHOULD** in this case return a `Location` header for the client to be able to track the execution.
  </Accordion>

  <Accordion title="PATCH method extends HTTP to update parts of the resource representation">
    Please refer to [RFC 5789](https://datatracker.ietf.org/doc/html/rfc5789).

    In contrast to PUT, only a specific subset of the resource properties should be changed. The set of changes is represented in a format called a patch document passed as
    payload and identified by a specific media type. The semantic is best described as "please change the resource identified by the URL according to my patch document".
    Generally, `PATCH` requests give clients the ability to update a partial representation of the resource. The syntax and semantics of the patch document is not defined
    in [RFC-5789](https://datatracker.ietf.org/doc/html/rfc5789) and must be described in the API specification by using one (or several) specific media types:

    * Media-type: `application/json`. Send a subset of the object representation. Replaces the values of any listed property. Completely replaces all items of an array property.
      Beware of the lack of control (and standard) such an implementation presents.
    * Media-type: `application/merge-patch+json`.  [JSON Merge Patch standard](https://datatracker.ietf.org/doc/html/rfc7396), which is a standardized way of achieving
      what's described above.
    * Media-type: `application/json-patch+json`. [JSON Patch](https://tools.ietf.org/html/rfc6902) standard, which gives proper support for granular array manipulations.
      It supports updating an array item identified *via* its index, but not *via* some of its properties.

    In general, as implementing the `PATCH` method can prove quite tricky, we recommend handling updates through the `PUT` method, which forces clients to send the complete
    representation of resource, but gives better control (idempotency and no side-effects).

    `PATCH` requests **SHOULD** support `If-Match` and `If-None-Match` headers in order to given clients a better control over concurrency and avoid lost updates.
  </Accordion>

  <Accordion title="DELETE requests are used to delete resources.">
    The semantic is best described as "please permanently delete the resource identified by the URL".

    `DELETE` requests **MUST** be idempotent.

    `DELETE` requests **MAY** be supported on collection resources, in order to support batch deletes. In this case, `DELETE` requests on collection endpoints **SHOULD**
    support query parameters in order to filter on the items of the collection to delete.

    `DELETE` request **MUST** return a 204 when successful. Any subsequent `GET` request **MUST** return a 404.

    `DELETE` request **MUST NOT** have any request body. When needed, please implement the corresponding feature through a POST request.

    `DELETE` requests **SHOULD** support `If-Match` and `If-None-Match` headers in order to given clients a better control over concurrency and avoid lost updates.
  </Accordion>

  <Accordion title="HEAD requests are used to retrieve the header information of single resources and resource collections.">
    This method has exactly the same semantics as `GET`, but only returns the headers (i.e. no response body).

    As a result, like a `GET` request, any `HEAD` request **MUST** be safe, idempotent, and **SHOULD** be cacheable.

    `HEAD` requests **SHOULD** be supported in order to give clients the ability to efficiently lookup whether large resources or collection resources have been
    updated in conjunction with the `If-Match` and `If-None-Match` headers.
  </Accordion>

  <Accordion title="Glossary: safe, idempotent, cacheable">
    * [safe](https://tools.ietf.org/html/rfc9110#section-9.2.1) - the operation semantic is defined to be essentially read-only, i.e. it must not change the server state.
      Reasonable use of a safe method is not expected to cause any harm, loss of property, or unusual burden on the origin server.
    * [idempotent](https://tools.ietf.org/html/rfc9110#section-9.2.2) - the operation keeps the same intended effect on the server state, whether it is executed once or
      multiple times. **Note:** this does not require that the operation is returning the same response or status code each time it is executed. Moreover, this does only
      affect what is visible to the API client, meaning, for example, that the server can keep logs of all executions.
    * [cacheable](https://tools.ietf.org/html/rfc9110#section-9.2.3) - a cacheable operation indicate that responses can be stored for future reuse. Safe methods responses
      are generally cacheable, as long as it is explicitly allowed in the response.
  </Accordion>
</AccordionGroup>

<Note>
  If an idempotent implementation of an HTTP method that is not supposed to be idempotent is required, then please consider using the
  `Idempotency-Key` HTTP header ([c.f. RFC](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header)).
</Note>

### \[103] **MUST** avoid having verbs in URLs

The API describes resources, so the only place where actions should appear is in the HTTP methods. In URLs, use only **nouns** and avoid verbs.

### \[104] **SHOULD NOT** show structural relationships in URIs

Showing structural relationships in URIs can be a good way of revealing dependencies and/or access rights scoping.

Nonetheless, it also:

* limits emergent uses, as it forces clients to iterate per parent resource.
* forces clients to know the parent resource id to GET the child.
* present the risk of having two URIs referencing the same collection resource (/parents/children vs parents/:id/children).
* can lead to pathing ambiguity (/parents/children vs /parents/:id)

If you choose nonetheless to have sub-resources, then you **SHOULD** avoid having more than 3 levels of depth. Going deeper increases
complexity as well as URL length (bear in mind some web browsers truncate URLs over 2,000 characters).

### \[105] **SHOULD** avoid pathing ambiguity

Pathing ambiguity naturally emerges from nested URL resources:

```http theme={null}
GET /employees/416 HTTPS/2
> Here, second URL segment is an ID.

GET /employees/addresses HTTPS/2
> Here, second URL segment is a child resource type.
```

### \[106] **MUST** use official HTTP status codes

You must only use official HTTP status codes consistently with their intended semantics. Official HTTP status codes are defined
via RFC standards and registered in the IANA Status Code Registry.

### \[107] **SHOULD** only use most common HTTP status codes

| Code                       | Methods                  | MUST document? | RFC                                                                            | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| :------------------------- | :----------------------- | :------------- | :----------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 200 OK                     | all                      | ✅              | [rfc9110](https://datatracker.ietf.org/doc/html/rfc9110#name-200-ok)           | General success response. Prefer a more specific success code when possible.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| 201 Created                | POST, PUT                | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-201-created)                | Returned on successful resource creation, even if response body is empty. Used along the Location header when the created resource URI is indeterminate for clients.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| 202 Accepted               | POST, PUT, PATCH, DELETE | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-202-accepted)               | The request was successful and will be processed asynchronously. Only applicable to methods which change the state on the server side.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| 204 No Content             | PUT, PATCH, DELETE       | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-204-no-content)             | Returned in place of a 200 if no response body is returned. Only applicable to methods which change the state of the resource.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| 304 Not Modified           | GET, HEAD                | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-304-not-modified)           | Returned whenever a conditional GET or HEAD request would have resulted in 200 response if the condition evaluated to false Usually: the resource has not been modified since the version passed via request headers If-Modified-Since or If-None-Match. For PUT, PATCH or DELETE requests, use 412 instead.                                                                                                                                                                                                                                                                                                                                                     |
| 400 Bad Request            | all                      | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-400-bad-request)            | Unspecific client error indicating that the server cannot process the request due to something that is perceived to be a client error (e.g. malformed request syntax, invalid request). Should also be delivered in case of input body fails business logic / semantic validation (instead of using 422).                                                                                                                                                                                                                                                                                                                                                        |
| 401 Unauthorized           | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-401-unauthorized)           | Actually “Unauthenticated”. The credentials are missing or not valid for the target resource. For an API, this usually means that the provided token or cookie is not valid. As this can happen for almost every endpoint, APIs should normally not document this.                                                                                                                                                                                                                                                                                                                                                                                               |
| 403 Forbidden              | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-403-forbidden)              | The user is not authorized to change this resource. For an API, this can mean that the request's token was valid, but was missing a scope for this endpoint. Or that some object-specific authorization failed. We recommend only documenting the second case.                                                                                                                                                                                                                                                                                                                                                                                                   |
| 404 Not Found              | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-404-not-found)              | The target resource was not found, either because it does not exist, or because the user cannot access it. This will be returned by most (not documented) paths on most APIs. For a PUT endpoint that does not support creation (only updates), then this might be returned if the resource does not exist. Apart from these special cases, this does not need to be documented.<br /><br />You should not return a 404 on a DELETE request on a resource that does not exist (or was already deleted), but a 204.<br /><br />You may return a 404 on write requests whenever the resource references another resource that is not accessible or does not exist. |
| 405 Method Not Allowed     | all                      | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-405-method-not-allowed)     | The request method is not supported for this resource. <br /><br />Using this response code on a documented endpoint only makes sense if it depends on some internal resource state whether a specific method is allowed. Do not use it unless you have such a special use case, but then make sure to document it, making it clear why a resource might not support a method.                                                                                                                                                                                                                                                                                   |
| 406 Not Acceptable         | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-406-not-acceptable)         | Resource only supports generating content with content-types that are not listed in the Accept header sent in the request.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 409 Conflict               | POST, PUT, PATCH, DELETE | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-409-conflict)               | The request cannot be completed due to conflict with the current state of the target resource. For example, you may get a 409response when updating a resource that is older than the existing one on the server, resulting in a version control conflict.<br /><br />If this is used, it **MUST** be documented.<br /><br />For successful robust creation of resources (PUT or POST) you should always return 200 or 204 and not 409, even if the resource exists already. If any If-\* conditional headers cause a conflict, you should use 412 and not 409. Only applicable to methods which change something.                                               |
| 410 Gone                   | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-410-gone)                   | The resource does not exist any longer (but did exist in the past), and will most likely not exist in the future. This can be used e.g. when accessing a resource that has intentionally been deleted. This normally does not need to be documented, unless there is a specific need to distinguish this case from the normal 404                                                                                                                                                                                                                                                                                                                                |
| 411 Length Required        | POST, PUT, PATCH         | ✅              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-411-length-required)        | The server requires a Content-Length header for this request. This is normally only relevant for large media uploads. The corresponding header parameter should be marked as required. If used, it MUST to be documented (and explained). Only applicable for methods with a request body.                                                                                                                                                                                                                                                                                                                                                                       |
| 412 Precondition Failed    | PUT, PATCH, DELETE       | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-412-precondition-failed)    | Returned for conditional requests (If-Match and If-None-Match) if the condition failed. Used for optimistic locking. Normally only applicable to methods that change something. For HEAD or GET requests, use 304 instead.                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 415 Unsupported Media Type | POST, PUT, PATCH         | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-415-unsupported-media-type) | The client did not provide a supported Content-Type for the request body. Only applicable to methods with a request body.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| 423 Locked                 | PUT, PATCH, DELETE       | ✅              | [rfc4918](https://tools.ietf.org/html/rfc4918#section-11.3)                    | Used for pessimistic locking.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| 428 Precondition Required  | all                      | ❌              | [rfc6585](https://tools.ietf.org/html/rfc6585#section-7.1)                     | Server requires the request to be conditional (If-Match and If-None-Match headers). Instead of documenting this response status, the required headers should be documented and marked as required.                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| 429 Too Many Requests      | all                      | ❌              | [rfc6585](https://tools.ietf.org/html/rfc6585#section-7.2)                     | The client is not abiding by the rate limits in place and has sent too many requests.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| 500 Internal Server Error  | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-500-internal-server-error)  | A generic error indication for an unexpected server execution problem.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| 501 Not Implemented        | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-501-not-implemented)        | Server cannot fulfill the request (usually implies future availability, e.g. new feature).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 503 Service Unavailable    | all                      | ❌              | [rfc9110](https://tools.ietf.org/html/rfc9110#name-503-service-unavailable)    | Service is temporarily down. Ideally, also return a Retry-After header giving clients the time to wait before retrying.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

### \[108] **MUST** return a Problem for 4xx and 5xx responses

Problem JSON is a standard way of describing errors. It is defined in the [RFC 9457](https://datatracker.ietf.org/doc/rfc9457/).
It provides extensible human and machine readable failure information, beyond the HTTP response status code.

All 4xx and 5xx status codes **MUST** respond with a Problem JSON.

The Problem JSON object **MUST** be served with the content-type `application/problem+json`.

### \[109] \[LUCCA-API] **MUST** indicate x-provider in the spec for each path

The `x-provider` OpenAPI extension is used to indicate which application offers concrete implementation for the given endpoint.
It makes it possible to bundle an application specification, with only their own subset of operations.

<CodeGroup>
  ```yml theme={null}
  paths:
      '/lucca-api/employees':
          x-provider: employee-directory
  ```
</CodeGroup>

### \[110] \[LUCCA-API] MUST use kebab-case for operationId in the OpenAPI spec for each endpoint

<CodeGroup>
  ```yml theme={null}
  paths:
      '/lucca-api/employees':
          get:
              operationId: list-employees
  ```
</CodeGroup>

### \[111] **SHOULD** avoid custom media types

Stick to standards, like `application/json`, `application/problem+json`, `application/hal+json`, etc…

You should avoid using custom media types like `application/com.luccasoftware.leave+json`. Custom media
types beginning with x bring no advantage compared to the standard media type for JSON, and make automated
processing more difficult.

### \[112] **MUST** be robust against excessive slashes

All services must normalize request paths before processing by removing duplicate and trailing slashes.
Hence, all these requests must resolve to the same resource:

<CodeGroup>
  ```http HTTP Redirects theme={null}
  GET /employees//12 HTTPS/2
  GET /employees/12/ HTTPS/2
  GET /employees/12 HTTPS/2
  ```
</CodeGroup>

### \[113] **SHOULD** avoid polymorphic endpoints

Polymorphic endpoints are harder to document, understand and use (both in reads and writes). So you should
avoid implementing such an endpoint unless the different sub-types are very similar and/or there are so many
sub-types that implementing a new endpoint for each would make the documentation harder to read.

If you choose to implement a polymorphic endpoint, please refer to the
[OpenAPI spec](https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/) in order to
properly document it.

<Note>You then **MUST** document the discriminator.</Note>

In the context of the Lucca API, the discriminator **MUST** be the reserved `type` property (if the root
resource is polymorphic, not a sub-object).

## Schemas

### \[200] **MUST** support the (Internet) JSON format

Use Internet JSON ([RFC 7493](https://tools.ietf.org/html/rfc7493)) to represent resource representations passed with HTTP in requests as well as responses bodies.

As a consequence, any JSON payload **MUST**:

* use [**UTF-8** encoding](https://tools.ietf.org/html/rfc7493#section-2.1)
* consist of [valid Unicode strings](https://tools.ietf.org/html/rfc7493#section-2.1), i.e. must not contain non-characters or surrogates, and
* contain only [unique member names](https://tools.ietf.org/html/rfc7493#section-2.3) (no duplicate names).

### \[201] **MUST** return JSON objects as top-level data structures

In a response body, you must always return a JSON object as a top level data structure to support future extensibility
(through adding additional properties).

### \[202] **MUST** name resources properties in camelCase

Why? Because we need to enforce consistent casing. We choose CamelCase to be consistent with the JavaScript syntax
(JSON stands for JavaScript Object Notation).

<CodeGroup>
  ```json JSON Example theme={null}
  	{
  		"startsOn": "2023-01-01",
  		"endsOn": "2023-01-31",
  		"leaveAccount": { ... }
  	}
  ```
</CodeGroup>

### \[203] **MUST** conform to semantics of reserved property names

Some resource representation properties are reserved and as such **MUST NOT** be used in any other way:

| Property name | Type                                   | Semantics                                                                                                                                          |                                                                                           |
| :------------ | :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| id            | string                                 | null                                                                                                                                               | Unique identifier of the resource in its collection.                                      |
| type          | string\<enum>                          | Name of the type of the resource. Should be equal to the name of its JSON schema in the spec. Used as the discriminator of a polymorphic resource. |                                                                                           |
| url           | string\<uri>                           | Absolute URL to the resource.                                                                                                                      |                                                                                           |
| totalCount    | integer\<int32>                        | null                                                                                                                                               | Counts all items of a collection (i.e. across all pages) that match the query parameters. |
| items         | array (not nullable, but may be empty) | Lists the representations of all ressources in the collection page.                                                                                |                                                                                           |
| embedded      | object                                 | Lists representations of related resources.                                                                                                        |                                                                                           |
| links         | object                                 | Lists relationships with other resources which are not structural (i.e. not already present as reference properties of the target resource).       |                                                                                           |

### \[204] **SHOULD** conform to type-dependent suffixes or prefixes

Properties of certain types **SHOULD** be named with a certain prefix or suffix to further indicate their type:

| Type                | Prefix              | Suffix |
| :------------------ | :------------------ | :----- |
| `string<date>`      | N/A                 | On     |
| `string<date-time>` | N/A                 | At     |
| `boolean`           | “is”, ”has“, “can”… | N/A    |

Regarding booleans: do name boolean properties with an affirmative phrase (`canDo` instead of `cantDo`) in order to avoid double negations ; and prefix them with `is`, `can`, or `has` whenever it adds value.

### \[205] **MUST** declare enum values as upper-snake case strings

Enumerations should be represented as string typed OpenAPI definitions of request parameters or schemas properties. Enum values (declared either via `enum` or `x-extensible-enum`) need to consistently use the upper-snake case format, e.g. VALUE or YET\_ANOTHER\_VALUE. This is in order to better discriminate them from other properties.

### \[206] **MUST** define a format for number and integer types

Please refer to the [OpenAPI spec](https://swagger.io/docs/specification/data-models/data-types/) for available formats.

This is enforced in order to prevent clients from guessing the precision incorrectly, and thereby changing the value unintentionally.

### \[207] **SHOULD** define a minimum and maximum value for number and integer types

### \[208] **MUST** use standard formats for date and time properties

You MUST use the string typed formats date, date-time, time, duration, or period for the definition of date and time properties. The formats are based on the standard [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) internet profile (a subset of ISO 8601).

### \[209] **SHOULD** use standard formats for time duration and interval properties

Properties that represent durations and time intervals **SHOULD** be represented as strings formatted as defined by ISO 8601 ([RFC 3339](https://www.rfc-editor.org/rfc/rfc3339)).

Please note that Extended Date/Time Format (EDTF) defines an extension to express open ended time intervals that could be very convenient in query parameters filtering.

### \[210] **SHOULD** enforce strong validation over types Date(Only), DateTime (floating) and DateTimeOffset.

This is in order to avoid weird behaviors due to fallbacks (particularly on the server’s timezone).

1. If the API expects a `DateTimeOffset`, then clients **MUST** send the offset. Otherwise, return a Problem.
2. If the API expects a `Date(Only)`, then clients **MUST** not send a time component (nor an offset, even though it’s valid). Otherwise, return a Problem.
3. You **CANNOT** compare a `DateTime` and a `DateTimeOffset`. Otherwise, return a Problem.

### \[211] **MUST** use standard formats for country, language and currency properties

| Type     | Standard                                                                                               | Description                  |
| :------- | :----------------------------------------------------------------------------------------------------- | :--------------------------- |
| Country  | [https://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) | Three letters country code.  |
| Language | [https://www.rfc-editor.org/rfc/rfc4646.html](https://www.rfc-editor.org/rfc/rfc4646.html)             | Language tag.                |
| Currency | [https://en.wikipedia.org/wiki/ISO\_4217](https://en.wikipedia.org/wiki/ISO_4217)                      | Three letters currency code. |

### \[212] **SHOULD** / **MUST** type ids as strings

Always use string rather than number type for identifiers in the Web layer, as it gives you more flexibility to evolve the identifier naming scheme.

Be aware that monotonically increasing numeric identifiers may reveal confidential information to non-privileged clients. In which case you may consider random generators.

### \[213] **SHOULD** avoid using UUID

UUIDs may solve common issues:

* Scaling problem in high frequency and near real-time use cases by making distribution easier.
* Idempotent creation by letting clients write IDs.

But they have major drawbacks:

* they do not convey any meaning
* they are harder to memorize
* they may make debugging harder
* they have a higher memory and bandwidth footprint
* they may be inefficient at the database level, especially when used as primary keys of highly referenced resources.
* they are unordered along their creation history

### \[214] **MAY** consider giving clients control over ids

Advantages:

* idempotent creation “by design”.
* reduces the risk of concurrency and “lost updates” problems.
* eases the synchronization between two systems by sharing ids, and as such, not needing to implement a mapping table.
* may make IDs easier to understand and memorize on the client’s side.

In which case, creation **SHOULD** be handled through a `PUT` request.

<CodeGroup>
  ```http HTTP Example theme={null}
  PUT /api/users/jdoe HTTPS/1.1
  { ... }
  ```
</CodeGroup>

### \[215] **SHOULD** avoid nullable array properties

Empty array values can unambiguously be represented as the empty list, i.e. **`[]`**.

### \[216] **MUST** avoid nullable boolean properties

A boolean is essentially a closed enumeration of two values, `true` and `false`. If the content has a meaningful null value, then we recommend replacing the boolean with enumeration of named values or statuses (e.g. “yes”, “no”, “undefined”).

### \[217] **MUST** consider null and absent properties as the same

OpenAPI makes it possible to mark a property as nullable (oas2: `nullable: true` ; oas3: `type: ['null', …]`) or non required (through the required property of an object).

A non-required property may be absent from the body. A nullable property may be null.

In other words, we could make a distinction between the two cases. But we decided against.

You **MUST** consider that an absent property is equivalent to declaring it `null`.

### \[218] **SHOULD** / **MUST** serialize null properties in responses

Even though an absent property is equivalent to it being `null`, we recommend avoiding elastic schema definitions. Always serializing all properties makes de-serializing easier in many languages and libraries.

### \[230] **MUST** use the common Money object

When describing an amount of money, then you must use the common `Money` object.

<CodeGroup>
  ```yml Money JSON Schema (YAML) theme={null}
  title: money
  type: object
  required:
      - amount
      - currency
  properties:
      amount:
          type: number
          format: decimal
          multipleOf: 0.0001
          example: 9.95
      currency:
          type: string
          description: 3 letter currency code as defined by ISO-4217
          format: 'iso-4217'
          examples: ['USD', 'EUR', 'CAD']
  ```
</CodeGroup>

You **MUST NOT** use this schema for inheritance. Treat it as a closed data type.

You **SHOULD** `$ref` to this schema in your OpenAPI spec.

### \[231] **MUST** use the common WorkEventDuration object

When describing the duration of a work-related event of an employee (e.g. a shift, a leave, etc…), then you must use the common `WorkEventDuration` object.

This gives you the ability to distinguish between two units: days and hours. Events in “days” unit have a duration defined as a fraction of a day of work (0.5 days might be 3.5 hours for an employee working 7h/day, and 4 hours for an employee working 8h/day).

Having a common definition grants us the ability to aggregate all work-related events of an employee and make calculations.

<CodeGroup>
  ```yaml WorkEventDuration JSON Schema (YAML) theme={null}
  title: WorkEventDuration
  type: object
  required:
      - iso
      - unit
  properties:
      iso:
          type: string
          format: duration
          description: > 
              Duration as defined in RFC 3339 internet profile 
              (subset of ISO 8601)
      value:
          type: number
          format: float
          multipleOf: 0.001
      unit:
          type: string
          enum:
              - DAYS
              - HOURS
          x-enumDescriptions:
              DAYS: >
                  The work event duration should be interpreted 
                  as a fraction of a work day.
              HOURS: >
                  The work event duration should be interpreted 
                  as a number of hours, minutes, seconds.
  examples:
      35h:
          iso: P1DT11H
          value: 35
          unit: HOURS
      218d:
          iso: P218D
          value: 218
          unit: DAYS
      negative:
          iso: -PT10H30M
          value: -10.5
          unit: HOURS
  ```
</CodeGroup>

You **MUST NOT** use this schema for inheritance. Treat it as a closed data type.

You **SHOULD** `$ref` to this schema in your OpenAPI spec.

You **SHOULD** only support write requests on the `iso` property.

### \[240] **MUST** use Problem schema for error responses

<CodeGroup>
  ```yaml Problem JSON Schema (YAML) theme={null}
  Problem:
  type: object
  properties:
      type:
      type: string
      description: >
                  A URI reference that identifies the problem type, ideally in the	context 
                  of the Lucca API.
                  **SHOULD** be an absolute URL to a page describing the nature of a problem.
                  **MAY** be a relative URI
              default: about:blank
      examples:
                  - "https://developers.luccasoftware.com/lucca-api/problems/not-found"
                  - "https://tools.ietf.org/html/rfc7231#section-6.5.4"
      title:
      type: string
      description: >
          A short summary of the problem type. Written in US-English and readable
          by anyone tech-savvy. As such, **MAY** not be suited for non technical 
          stakeholders and not localized in the user's language.
      example: The expense was not found.
      status:
      type: integer
      format: int32
      description: >
          The HTTP status code generated by the origin server for this occurrence
          of the problem.
      minimum: 100
      maximum: 600
      exclusiveMaximum: true
      detail:
      type: string
      description: >
          A human readable explanation specific to this occurrence of the
          problem that is helpful to locate the problem and give advice on how
          to fix it. Written in US-English and readable by ayone tech-savvy, 
          **MAY** not be suited for non technical stakeholders and **MAY** not 
          be localized in the user's language.
      example: > 
                  The expense #123 was not found on this server. You may double check 
                  the given id or make sure you have access to it.
          errors:
              type: object
              description: >
                  Lists all parameters or fields that violated validation rules.
                  For each member, gives a list of human readable explaining the
                  violation. Written in US-English and readable by anyone tech-savvy,
                  **MAY** not be suited for non technical stakeholders and **MAY** not
                  be localized in the user's language.
              additionalProperties:
                  type: array
                  items:
                      type: string
              examples:
                  - limit:
                          - "The limit query parameter cannot exceed max value of 1000"
  ```
</CodeGroup>

### \[250] \[LUCCA-API] MUST conform to the Event schema for (webhook) events

```
...
```

### \[251] \[LUCCA-API] MUST follow naming convention for event topics

<Codegroup>
  ```abnf ABNF Syntax theme={null}
  topic = resource-name "." event-type
  resource-name = 1*ALPHA
  event-type = "created" / "updated" / "deleted"
  ```
</Codegroup>

## Query Parameters

### \[301] **MUST** not deviate from reserved query parameters intended semantic

Some query parameters are reserved and as such **MUST NOT** be used in any other way:

| Name      | Type                                                                | Semantics                                                                                                                 |
| :-------- | :------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------ |
| `page`    | `string`                                                            | Cursor to the page.                                                                                                       |
| `limit`   | `integer<int32>`                                                    | Number of items per page.                                                                                                 |
| `include` | <code>Array\<string\<'embedded' \| 'links' \| 'totalItems'>></code> | Control over the inclusion of embedded resource, the total count of a collection items and/or links to related resources. |
| `sort`    | `Array<string<enum>>`                                               | Control over the sorting of a collection's items.                                                                         |

Outside of the Lucca API, the page parameter **MAY** be an integer (offset-based pagination) rather than a cursor.

### \[310] **MUST** define a default sorting strategy for consistency

This default sorting strategy should apply to a unique property. For this reason,
it is recommended to sort on the reserved `id` property by default.

### \[311] **MAY** give clients control over the ordering of a collection's items

Giving clients control over the ordering of items of a collection is considered good practice
and can ease emergent uses.

### \[312] **MUST** conform to the standard when giving clients control over sorting

Sorting is handled through a sort query parameter whose BNF grammar is:

<CodeGroup>
  ```bnf BNF Syntax theme={null}
  <sort>                  ::= "-|+"? <property> ( "," <property> )*
  <property>              ::= <strictString> ( "." <strictString> )*
  <strictString>          ::= ( <char> | <digit> | "_" | "-" )+
  ```
</CodeGroup>

### \[313] **SHOULD** name sort enum values with the ressource properties names (w/ prefix)

Sorting options should be named in compliance with the actual ressource property names the sorting is applied on.

<CodeGroup>
  ```text Examples theme={null}
  ?sort=lastName,firstName
  ?sort=-age
  ```
</CodeGroup>

### \[320] **SHOULD** name filtering query parameters in conformity with the relevant property name when applying equality on an existing property

When query parameters are used as a way to filter resources based on the value of one of their properties, then the query
parameter **SHOULD** be named with the same name as the relevant property.

### \[321] **MUST** use camelCase for filtering query parameter names

As a result of the previous rule, query parameters **MUST** be named using the same casing as properties: camelCase.

<CodeGroup>
  ```http HTTP Example theme={null}
  GET /lucca-api/employees?payrollIdentifier=00123 HTTPS/1.1
  ```
</CodeGroup>

### \[322] **SHOULD** stick to the JSON object structure (JSON path) when naming query parameters

When these query parameters filter on a nested property (i.e. the property of an object property in the resource representation),
then the query parameter name **SHOULD** stick to the JSON path to said property (i.e. list the properties from the root object,
separated with a dot “.” character).

Examples:

<CodeGroup>
  ```text Example #1 theme={null}
  ?department.id=12
  ?department.head.lastName=Doe
  ```

  ```text Example #2 theme={null}
  /employees?sort=lastName
  ```
</CodeGroup>

### \[323] **SHOULD** avoid default values on filtering query parameters.

Unless it absolutely makes sense, in which case the default value **MUST** be documented in the OpenAPI specs.

### \[324] **SHOULD** support an array of values on equality operator filtering

When applying an equality filter on one property of the resource, then you should support multiple values.
In this case, values must be serialized as a comma-separated list:

<CodeGroup>
  ```text Example theme={null}
  ?status=pending,approved,denied
  ```
</CodeGroup>

### \[325] **SHOULD** support date-range values when filtering on date or date-time properties through a `{propName}.between` named query parameter

TODO

### \[326] **MUST** represent date-range query parameter values in compliance with ISO 8601:

<CodeGroup>
  ```ABNF ABNF syntax theme={null}
  date-fullyear         = 4DIGIT
  date-month            = 2DIGIT  ; 01-12
  date-mday             = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on month/year
  time-hour             = 2DIGIT  ; 00-23
  time-minute           = 2DIGIT  ; 00-59
  time-second           = 2DIGIT  ; 00-58, 00-59, 00-60 based on leap second rules
  time-secfrac          = "." 1*DIGIT
  time-numoffset        = ("+" / "-") time-hour ":" time-minute
  time-offset           = "Z" / time-numoffset

  iso-date              = date-fullyear "-" date-month "-" date-mday
  iso-date-time         = iso-date "T" time-hour ":" time-minute ":" time-second [time-secfrac]
  iso-date-time-offset  = iso-date-time time-offset

  date-range                  = (iso-date / "..") "--" (iso-date / "..")
  date-time-range             = (iso-date-time / "..") "--" (iso-date-time / "..")
  date-time-offset-ranges     = (iso-date-time-offset / "..") "--" (iso-date-time-offset / "..")
  ```

  ```text Query examples theme={null}
  # closed interval
  ?startsOn.between=2024-01-01--2024-01-31
  # open-handed (left)
  ?startsOn.between=..--2024-01-31
  # open-handed (right)
  ?startsOn.between=2024-01-01--..
  ```
</CodeGroup>

<Note>
  The canonical notation with a “/” (forward slash) delimiter between dates
  **SHOULD** not be used as it could break URLs when used as query parameter values.
</Note>

You **MAY** choose to support date(-time)-ranges defined with a duration component.

You **SHOULD** support open-handed ranges (i.e. with a “..” start or end).

### \[327] **MUST** treat date-ranges as closed intervals, and date-time-ranges as open-handed intervals

Why? Because this is the most common human way of apprehending date and date-time ranges.

<CodeGroup>
  ```bnf theme={null}
  2024-01-01--2024-01-31 --> Includes Jan. 31st
  2024-01-01T00:00:00Z--2024-01-02T00:00:00Z --> Does not include midnight of Jan. 2nd
  ```
</CodeGroup>

### \[340] **MAY** support embedding controls in order to give clients the ability to expand responses and include related ressources and/or optional complementary properties

Giving API clients control over response exansion is a way of making integrations easier.

Nonetheless, be aware that such features may prove costly, due to:

* potential poor performance on most complex JOIN requests ;
* high payload weight ;
* cache fragmentation ;
* cache invalidation ;
* complexity when parsing elastic response.

### \[341] **MUST** stick to the embedding convention when implementing embedding

Paging is handled through two query parameters:

| Parameter name | Parameter value type         | Example      | Description                                       |
| :------------- | :--------------------------- | :----------- | :------------------------------------------------ |
| page           | `<string &#124; int<int32>>` | `?page=2`    | The identifier of the page to retrieve.           |
| limit          | `int<int32>`                 | `?limit=100` | The page size. Subject to default and max values. |

### \[360] **MUST** implement paging on all collections whose length is not controlled

Whenever representing a collection of resources whose maximum size is not constant and can prove high,
then make sure to implement paging. Paging is the key to ensuring satisfactory performance.

### \[361] **MUST** support cursor-based paging

Cursor-based paging offers better performance than index-based paging, but at the cost of one feature:
API clients must iterate through each page (they cannot randomly access a given page), as the cursor of
a page is obtained through retrieving the previous or next one.

### \[362] **SHOULD** support index-based paging

On top of allowing random-access, index-based paging is also more common and more readily comprehensible
by humans.

### \[361] **SHOULD** have a “low“ default page size (limit)

Having a low default page size:

* Ensures satisfactory response times of random requests.
* Encourages clients to properly implement paging.

We recommend having a default page size between 10 and 25.

### \[362] **MUST** have a “reasonable” max page size (limit)

For the same reasons as above.

We recommend not exceeding 100 items per page.

### \[363] **SHOULD** strive to a coherent default paging strategy over the whole API

Monotony reduces complexity. As such, make sure your default as well as max page size are the same for all collections.

### \[364] **MUST** support paging links (next, prev)

Paging links consists in giving API clients links to the previous and next page when
retrieving a page of resources.

<Note>This is absolutely mandatory when implementing cursor-based paging.</Note>

## Embedding

### \[400] **MAY** support embedding in order to given clients control over response expansion

Reponse expansion is considered a good practice as it may reduce the number of required HTTP
requests and as such make integrations easier.

### \[401] **MUST** conform to the convention when representing embedded ressources

The embedded representation of a resource **MUST** be in the reserved `embedded` response property
(at the root object level).

The `embedded` property **MUST** be a JSON object whose keys are the name of the resources `types`, and its values
are a JSON object whose keys are the embedded resources `ids` and values the related representation.

<CodeGroup>
  ```json JSON Example theme={null}
  {
      "embedded": {
          "employee": {
              "416": {
                  "id": "416",
                  "type": "employee",
                  "url": "...",
                  "givenName": "John",
                  "familyName": "Doe"
              }
          }
      }
  }
  ```
</CodeGroup>

### \[402] **MAY** offer partial representations of embedded ressources

Resource representations embedded in the reserved `embedded` property **MAY** be partial, i.e.
only serialize a subset of the related resource properties.

Nonetheless, The reserved `id`, `type` and `url` properties **MUST** always be included.

### \[403] **MUST** evaluate access rights when embedding related ressource representations

You **MUST** make sure the authenticated user has access to the resource when embedding it in
the response.

### \[404] **SHOULD** invalidate HTTP cache when embeddable ressource state changes

When representing an embedded related resource, then any change to this embedded resource also
changes the representation of the embedding representation.

As a result, the HTTP cache of the embedding resource **SHOULD** be invalidated whenever one of
its embedded resources changes.

<Warning>
  This is a **SHOULD** and not a **MUST**. Consequently, embedded resources representations **MAY** be stale from cache.
</Warning>

<Note>
  This is why the embedding is done at root level rather than nested in the embedding resource representation.
</Note>

### \[405] **SHOULD NOT** trigger a (webhoook) event when an embeddable ressource state changes

In order to avoid events propagation, avoid triggering events on the embedding resource whenever
one of its embedded resource is changed, except if the embedding resource bears a property that references
this embedding resource.

In other words: you **SHOULD** trigger an event whenever an intrinsic attribute of the resource changes ;
and embedded representations are not intrinsic attributes.

## Headers

### \[600] **MUST** use hyphen-separated Pascal-Case and avoid “X-” prefix when naming headers

Custom headers **SHOULD NOT** be prefixed with “X-” (this practice was deprecated along with
[RFC-6648](https://datatracker.ietf.org/doc/html/rfc6648)).

Header **MUST** be named using hyphen-separated PascalCase.

### \[601] **SHOULD** stick to standard HTTP headers

You **SHOULD** stick to standard HTTP headers whenever possible.

### \[602] **MUST** respect the intended semantic for reserved HTTP headers

Some custom headers are reserved for the Lucca API and as such **MUST NOT** be used in any other way.

## Versioning

### \[700] **SHOULD** avoid versioning APIs

Versioning an API should be seen as a last resort when implementing APIs, as it breaks integrations.

### \[701] **SHOULD** reduce breaking changes through proper change management

Prefer additions to deletions / modifications.

Have a rather “lax” definition of breaking changes. For example: clients should consider all ressources extensibles without breaking. Same with enumerations.

### \[702] **MUST** version the Lucca API

The major quality expected of the Lucca API is its stability for clients. As we cannot prevent all breaking changes, a versioning must be implemented.

### \[703] **MUST** handle API versioning through the `Api-Version` HTTP header (both requests and responses)

<CodeGroup>
  ```http HTTP Example theme={null}
  GET /lucca-api/employees HTTP/1.2
  Host: example.ilucca.net

  > Request
  Api-Version: 2024-01-22
  Accept: application/json

  < Response
  Api-Version: 2024-01-01
  Content-Type: application/json

  { ... }
  ```
</CodeGroup>

### \[704] **SHOULD** avoid default version

Either make the `Api-Version` HTTP header required, or make it possible for clients to “lock” a specific version (e.g. API key based).

### \[705] **SHOULD** name version with their release date

You may implement version selection through a “as of” behaviour: the server will select the API version that exactly matches the given version or is the closest prior one.

### \[706] **MUST** use the `Deprecation` and `Sunset` HTTP headers to convey an API version lifecycle

For the `Deprecation` HTTP header, refer to the [draft-ietf-httpapi-deprecation-header-03](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-deprecation-header).

For the `Sunset` HTTP header, refer to [RFC 8594](https://datatracker.ietf.org/doc/html/rfc8594).

<CodeGroup>
  ```http HTTP Example theme={null}
  GET /lucca-api/employees HTTP/1.2
  Host: example.ilucca.net

  > Request
  Api-Version: 2018-01-01
  Accept: application/json

  < Response
  Api-Version: 2018-01-01
  Deprecation: 2020-04-01
  Sunset: 2025-01-01
  ```
</CodeGroup>

### \[707] \[Lucca API] **MUST** support deprecated version for at least 6 months

Once an API version has been deprecated, then it must stay available to all clients for at least 6 months. This date is  ideally indicated in the `Sunset` HTTP response header.

### \[708] \[Lucca API] **MUST NOT** deprecate an API version prior to 6 months after its initial release

Once an API version is released, it may not be deprecated before a 6 months time period has passed.

### \[709] **MUST** notify clients whenever an API version is deprecated

The information should be available to all clients, and you should be extra zealous and notify those that actively use it.

### \[710] **MAY** break an already released API version in order to fix bugs, unexpected behaviors or security and performance issues.

In other words: if the deployed API version is not compliant with the spec, then you may fix it even though it could lead to breaking changes (as long as the fix makes it compliant with the spec).

## Cache

### \[730] **SHOULD** implement default HTTP cache behavior

You should always be explicit regarding cacheability. As **default**, when not implementing cache, servers and clients should always set the `Cache-Control` header to `Cache-Control: no-store` (rather than `no-cache`).

As a reminder:

* `no-cache`: responses may be cached but should be validated before use.
* `no-store`: responses may not ever be cached.

### \[731] **SHOULD** support HTTP cache on endpoints exposing stable resources

HTTP Caching is the prime means of building scalable APIs.

### \[732] **MUST** conform to the standard semantic of HTTP methods when implementing HTTP cache

Please refer to [HTTP methods cacheability](#102-must-conform-to-http-methods-standard-semantics).

## Events

### \[900] **SHOULD** implement events for all mutable resources

Events give API clients more optimal ways of integrating to the Lucca API
(polling can prove costly and complex).

### \[901] **SHOULD** offer "at-least-once" guarantee to receivers

As a reminder:

* “at-most-once”: message may be lost, but if not, will only be delivered once.
* “at-least-once”: message may never be lost, but may be delivered more than once.
* “exactly-once”: message may never be lost and will never be delivered more than once.

“Exactly-once” is the most difficult delivery guarantee to implement. It sure is friendly
to API clients, but it has a high cost for the system's performance and complexity.

Therefore, when implementing the “at-least-once” guarantee, make sure events receivers
are idempotent and handle message duplication correctly.

### \[902] **SHOULD** avoid ad hoc events and stick to CRUD RESTful events

An Event represents a change in an application state that might be of interest to third-party apps.

In order to be properly coordinated with the REST API, an Event must always be a change that is in relation
to a single resource represented in the API. In other words:

* an event **MUST** be linked to one affected REST resource.
* an event **MUST** be sent whenever a resource's (that is subject to events) representation in the API changes
  (outside of `embedded` and `links`).

In other words, embrace data-change events (e.g. `job-position.created`) and stay clear of business-events
(e.g. `employee.promoted`) as well as free-form events (e.g. `employee-10-years-anniversay`).

### \[903] **MUST** conform to the event schema and topic conventions

<Note>“Topic” is synonym to “type of event”.</Note>

The event schema is imposed and described in the [API Reference](../api-reference/latest/events/event).

<Note>
  Events are “fat” (rather than “thin”), i.e. contain the representation of the related
  resource in order to improve the development experience among receivers.
</Note>

Topics naming **MUST** conform to the following conventions:

<CodeGroup>
  ```bnf BNF Syntax theme={null}
  <op>    ::= "created" | "updated" | "deleted"
  <topic> ::= <resource.type> '.' <op>
  ```

  ```text Examples theme={null}
  employee.created
  employee.updated
  employee.deleted

  leave.created
  leave.updated
  leave.created
  ```
</CodeGroup>

### \[904] **MUST** reserve the "event" term to RESTful events

You may add an affix though, for example: `calendar-event`.

### \[905] **SHOULD** support the `updatedAttributes` on `*.updated` topics

Giving receivers the list of updated attributes on `*.updated` events.

When implementing this feature, you **SHOULD** serialize a JSON object whose
keys are the updated attributes and whose values are their previous value.

### \[906] **MUST** sign events when sending them to webhooks

Ensure authenticity of the event (a fake event might be injected or the data
of a legitimate event might be forged). To make sure an event has not been tampered
with, a cryptographic signature must be used, like HMAC (Hash-based Message Authentication Code).

The sender **MUST** sign the event payload with a shared secret and includes the signature
in the `Lucca-Signature` HTTP header.

This offers the following guarantees:

1. authentication: authenticates the sender ;
2. non-repudiation: makes sure the sender cannot deny having sent the event ;
3. integrity: makes sure the content of the event was not tampered with in transit.

In order to protect receivers againts replay attacks (an attacker might record traffic and
play it back later), make sure the signature depends on a timestamp that matches the moment
the event delivery is attempted.

Reeivers need to validate the signature and the timestamp contained in the event
(a tolerance of +/- 5 minutes should be applied). In other words, any event older than
5 minutes should be automatically rejected by the subscriber.

### \[907] **SHOULD** enforce “fast” responce times on receivers through a timeout

Prevent event flooding: a receiver endpoint might get flooded with events. Best practice is
for receivers to “acknowledge receipt of events fast, and queue events for asynchronous
processing”.

A timeout can help enforce satisfactory response times on receivers (e.g.: Slack imposes
a very short 3 seconds timeout on receivers). Otherwise, deliveries will be suspended.

### \[908] **MUST NOT** deliver events through uncrypted HTTP requests

For obvious security reasons.

### \[909] **MUST** version events along the API

When the API is versioned, then make sure your events are as well (given that the
representations of resources embedded in events payload are versioned).

When multiple API versions are live, then make sure to generate as many events as
there are ongoing versions (one for each version).

### \[920] **MAY** support the cloudevents format

CloudEvents is a [specification](https://github.com/cloudevents/spec) for describing
event data in common formats to provide interoperability across services, platforms and systems.
