6.2.1. [NONBLOCK_PULL_REST] Not Blocking Pull REST¶
Quando il profilo viene implementato con tecnologia REST, DEVONO essere rispettate le seguenti regole:
- La specifica dell’interfaccia dell’erogatore DEVE dichiarare tutti i codici di stato HTTP restituiti con relativo schema della risposta, oltre che ad eventuali header HTTP restituiti;
- La specifica dell’interfaccia DEVE dichiarare gli schemi delle richieste insieme ad eventuali header HTTP richiesti;
- Al passo (1), il fruitore DEVE utilizzare il verbo HTTP POST;
- Al passo (2), l’erogatore DEVE fornire insieme all’acknowledgement della richiesta, un URL per interrogare lo stato di processamento utilizzando HTTP header Location , il codice HTTP di stato DEVE essere HTTP status 202 Accepted a meno che non si verifichino errori;
- Al passo (3), il fruitore DEVE utilizzare il percorso di cui al passo (2) per richiedere lo stato della risorsa; il verbo HTTP utilizzato deve essere GET;
- Al passo (4) l’erogatore indica, sulla base dello stato del processamento, che l’operazione: * 4a. non è completata (HTTP status 200 OK) * 4b. che la risorsa finale è pronta (HTTP status 303 See Other) all’URL indicato nell’ HTTP header Location ;
- Al passo (5), il fruitore DEVE recuperare la risorsa con una richiesta HTTP method GET all’URL indicato in (4b.);
- Al passo (6) l’erogatore risponde con la rappresentazione della risorsa, il codice HTTP restituito è HTTP status 200 OK.
6.2.1.1. Regole di processamento¶
Al termine del processamento delle richieste, l’erogatore deve fare uso dei codici di stato HTTP rispettando la semantica. In particolare, al ricevimento della richiesta da parte del fruitore, l’erogatore:
- DEVE verificare la validità sintattica e semantica dei dati in ingresso
- DEVE, in caso di dati errati, restituire HTTP status 400 Bad Request fornendo nel body di risposta dettagli circa l’errore;
- DOVREBBE, in caso di representation semanticamente non corretta, ritornare HTTP status 422 Unprocessable Entity;
- DEVE, se qualcuno degli ID nel path o nel body non esiste, restituire HTTP status 404 Not Found, indicando nel body di risposta quale degli ID è mancante;
- PUÒ, se ipotizza che la richiesta sia malevola, ritornare HTTP status 400 Bad Request o HTTP status 404 Not Found;
- DEVE, in caso di errori non dipendenti dalla richiesta, restituire HTTP status 5xx rispettando la semantica degli stessi;
- DEVE, ricevuta la richiesta, restituire HTTP status 202 Accepted.
- In caso di ricezione corretta della risposta, il fruitore DEVE restituire HTTP status 200 OK, riempiendo il body di risposta con il risultato dell’operazione.
- In caso di errore al momento di ricezione della risposta da parte del fruitore, è possibile definire meccanismi specifici per la ritrasmissione della risposta o della richiesta.
NB: I messaggi di errore devono essere utili al client ma NON DEVONO rivelare dettagli tecnici e/o informazioni riservate.
6.2.1.2. Esempio¶
Specifica Servizio Server
https://api.ente.example/rest/nome-api/v1/openapi.yaml
openapi: 3.0.1
info:
title: RESTbusywaiting
version: "1.0"
description: |-
Questo file descrive semplicemente i metodi di un'API
e non indica tutte le informazioni di metadatazione che
normalmente vanno inserite.
license:
name: Apache 2.0 License
url: http://www.apache.org/licenses/LICENSE-2.0.html
paths:
/tasks/queue:
post:
description: Crea in maniera asincrona un task o una risorsa.
operationId: PushMessage
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MType'
responses:
202:
description: Preso carico correttamente
headers:
Location:
description: URL dove verificare lo stato
required: true
schema:
type: string
format: uri
'400':
$ref: '#/components/responses/400BadRequest'
default:
$ref: '#/components/responses/default'
/tasks/queue/{id_task}/:
get:
description: Verifica lo stato del task o risorsa
operationId: CheckStatus
parameters:
- $ref: '#/components/parameters/id_task'
responses:
200:
description: |-
Lo stato del task o della risorsa.
content:
application/json:
schema:
$ref: '#/components/schemas/TaskStatus'
'303':
description: Task Completato
content:
application/json:
schema:
$ref: '#/components/schemas/TaskStatus'
headers:
Location:
description: URL dove prelevare il risultato
required: true
schema:
type: string
format: uri
'400':
$ref: '#/components/responses/400BadRequest'
'404':
$ref: '#/components/responses/404NotFound'
default:
$ref: '#/components/responses/default'
/tasks/result/{id_task}/:
get:
description: Recupera il risultato del task o la risorsa
operationId: RetriveResource
parameters:
- $ref: '#/components/parameters/id_task'
responses:
200:
description: Il risultato del task o la risorsa
content:
application/json:
schema:
$ref: '#/components/schemas/MResponseType'
'400':
$ref: '#/components/responses/400BadRequest'
'404':
$ref: '#/components/responses/404NotFound'
default:
$ref: '#/components/responses/default'
components:
parameters:
id_task:
name: id_task
in: path
required: true
schema:
type: string
responses:
400BadRequest:
description: Richiesta non accoglibile
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
404NotFound:
description: Identificativo non trovato
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
default:
description: |-
Errore inatteso. Questo viene ritornato nel caso ci sia
un errore inatteso. Non vanno mai esposti i dati interni
del server.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
schemas:
TaskStatus:
type: object
properties:
status:
type: string
enum: [pending, completed]
example: pending
message:
type: string
MType:
type: object
properties:
a:
$ref: '#/components/schemas/AComplexType'
b:
type: string
MResponseType:
type: object
properties:
c:
type: string
AComplexType:
type: object
properties:
a1s:
type: array
items:
type: string
a2:
type: string
ErrorMessage:
type: object
properties:
detail:
description: |
A human readable explanation specific to this occurrence of the
problem.
type: string
instance:
description: |
An absolute URI that identifies the specific occurrence of the problem.
It may or may not yield further information if dereferenced.
format: uri
type: string
status:
description: |
The HTTP status code generated by the origin server for this occurrence
of the problem.
exclusiveMaximum: true
format: int32
maximum: 600
minimum: 100
type: integer
title:
description: |
A short, summary of the problem type. Written in english and readable
for engineers (usually not suited for non technical stakeholders and
not localized); example: Service Unavailable
type: string
type:
default: about:blank
description: |
An absolute URI that identifies the problem type. When dereferenced,
it SHOULD provide human-readable documentation for the problem type
(e.g., using HTML).
format: uri
type: string
Il fruitore richiede la risorsa M, e l’erogatore risponde dichiarando di aver preso in carico la richiesta.
Endpoint https://api.ente.example/rest/nome-api/v1/resources/1234/M
- Request:
POST /rest/nome-api/v1/resources/1234/M HTTP/1.1
Host: api.ente.example
Content-Type: application/json
{
"a": {
"a1": [1, "…", 2],
"a2": "Stringa di esempio"
},
"b": "Stringa di esempio"
}
- Response
HTTP/1.1 202 Accepted
Content-Type: application/json
Location: /rest/nome-api/v1/resources/1234/M/8131edc0
{
"status": "accepted",
"message": "Preso carico della richiesta",
"id": "8131edc0"
}
Quindi il fruitore verifica lo stato dell’esecuzione di M (3). L’erogatore ritorna un payload diverso a seconda dei casi: - processamento ancora in atto (4a) - e di processamento avvenuto (4b).
Endpoint
https://api.ente.example/rest/nome-api/v1/resources/1234/M/8131edc0
- Request
GET /rest/nome-api/v1/resources/1234/M/8131edc0 HTTP/1.1
Host: api.ente.example
4a. Response (HTTP status 200 OK)
HTTP/1.1 200 OK
Host: api.ente.example
Content-Type: application/json
{
"status": "processing",
"message": "Richiesta in fase di processamento"
}
4b. Response (HTTP status 303 See Other)
Poiché al termine del processamento il client viene rediretto verso la risorsa finale, il payload deve contenere solamente le informazioni utili al redirect. Questo anche perché alcuni client potrebbero seguire direttamente l”HTTP header Location ignorando il payload HTTP status 303 See Other e ritornando invece quello indicato nel punto 5.
HTTP/1.1 303 See Other
Content-Type: application/json
Content-Location: /rest/nome-api/v1/resources/1234/M/8131edc0
Location: /rest/nome-api/v1/resources/1234/M/8131edc0/result
{
"status": "done",
"message": "Processamento completo",
"href": "https://api.ente.example/rest/nome-api/v1/resources/1234/M/8131edc0/result"
}
Di seguito un esempio di chiamata con cui il fruitore richiede l’esito della sua richiesta.
Endpoint
https://api.ente.example/rest/nome-api/v1/resources/1234/M/8131edc0/result
- Request:
GET /rest/nome-api/v1/resources/1234/M/8131edc0/result HTTP/1.1
Host: api.ente.example
- Response:
HTTP/1.1 200 OK
Host: api.ente.example
Content-Type: application/json
{"c": "OK"}