Qual è il vantaggio di utilizzare REST anziché HTTP non REST?


Risposte:


163

Non credo che si otterrà una buona risposta a questo, in parte perché nessuno è d'accordo davvero su ciò che REST è . La pagina di Wikipedia è piena di parole d'ordine e di spiegazioni chiare. La pagina di discussione merita una scrematura solo per vedere quante persone non sono d'accordo su questo. Per quanto posso dire, REST significa questo:

Invece di avere setter e getter URL nome casuale e utilizzare GETper tutti i getter e POSTper tutti i setter, cerchiamo di avere gli URL identificare le risorse, e quindi utilizzare le azioni HTTP GET, POST, PUTe DELETEper fare cose per loro. Quindi invece di

GET /get_article?id=1
POST /delete_article   id=1

Lo faresti

GET /articles/1/
DELETE /articles/1/

E quindi POSTe PUTcorrispondono alle operazioni "crea" e "aggiorna" (ma nessuno concorda in quale direzione).

Penso che gli argomenti della cache siano sbagliati, perché le stringhe di query sono generalmente memorizzate nella cache e inoltre non è necessario utilizzarle. Ad esempio, django rende qualcosa del genere molto semplice e non direi che fosse REST:

GET /get_article/1/
POST /delete_article/     id=1

O includi semplicemente il verbo nell'URL:

GET /read/article/1/
POST /delete/article/1/
POST /update/article/1/
POST /create/article/

In tal caso GETsignifica qualcosa senza effetti collaterali e POSTsignifica qualcosa che modifica i dati sul server. Penso che questo sia forse un po 'più chiaro e più facile, soprattutto perché puoi evitare l'intera cosa PUT-vs- POST. Inoltre, puoi aggiungere più verbi se lo desideri, quindi non sei legato artificialmente a ciò che offre HTTP. Per esempio:

POST /hide/article/1/
POST /show/article/1/

(O qualunque cosa, è difficile pensare ad esempi fino a quando non accadono!)

Quindi, in conclusione, ci sono solo due vantaggi che posso vedere:

  1. L'API Web potrebbe essere più pulita e più facile da comprendere / scoprire.
  2. Quando si sincronizzano i dati con un sito Web, è probabilmente più semplice utilizzare REST perché si può semplicemente dire synchronize("/articles/1/")o altro. Questo dipende fortemente dal tuo codice.

Tuttavia, penso che ci siano alcuni svantaggi piuttosto grandi:

  1. Non tutte le azioni sono facilmente mappabili su CRUD (creare, leggere / recuperare, aggiornare, eliminare). Potresti non avere nemmeno a che fare con le risorse del tipo di oggetto.
  2. È uno sforzo extra per vantaggi discutibili.
  3. Confusione su come PUTe intorno POST. In inglese significano cose simili ("Ho intenzione di mettere / pubblicare un avviso sul muro.").

Quindi, in conclusione, direi: a meno che tu non voglia davvero impegnarti di più, o se il tuo servizio è davvero ben collegato alle operazioni CRUD, salva REST per la seconda versione della tua API.


Ho appena riscontrato un altro problema con REST: non è facile fare più di una cosa in una richiesta o specificare quali parti di un oggetto composto si desidera ottenere. Ciò è particolarmente importante sui dispositivi mobili in cui il tempo di andata e ritorno può essere significativo e le connessioni non sono affidabili. Ad esempio, supponiamo di ricevere post su una sequenza temporale di Facebook. Il modo "puro" di RESTO sarebbe qualcosa di simile

GET /timeline_posts     // Returns a list of post IDs.
GET /timeline_posts/1/  // Returns a list of message IDs in the post.
GET /timeline_posts/2/
GET /timeline_posts/3/
GET /message/10/
GET /message/11/
....

Che è un po 'ridicolo. L'API di Facebook è un ottimo IMO, quindi vediamo cosa fanno:

Per impostazione predefinita, la maggior parte delle proprietà degli oggetti vengono restituite quando si effettua una query. È possibile scegliere i campi (o le connessioni) che si desidera restituire con il parametro di query "campi". Ad esempio, questo URL restituirà solo l'id, il nome e l'immagine di Ben: https://graph.facebook.com/bgolub?fields=id,name,picture

Non ho idea di come faresti una cosa del genere con REST, e se lo facessi se conterebbe comunque come REST. Sicuramente ignorerei chiunque cerchi di dirti che non dovresti farlo (soprattutto se il motivo è "perché non è RIPOSO")!


4
POST e PUT sono pensati per essere utilizzati per HTTP RFC. In questo caso, PUT significa creare / aggiornare qualcosa in una posizione specifica - il che si verifica dipende dal fatto che qualcosa sia già presente nell'URI (ed è anche idempotente) mentre POST significa che chiedi al servizio web di determinare dove posizionare ciò che stai inviandolo - e quindi ti restituisce l'URI (quindi è solo creare). Non posso davvero lamentarmi dell'inglese, non quando è completamente spento usare DELETE quando ti riferisci a qualcosa al di fuori del computer. Mi chiedo cosa fare riguardo al problema sollevato nella tua modifica, però: P
Nan L

7
L'esempio dell'API di Facebook mi sembra REST (in realtà molto più che i tuoi esempi usano i verbi negli URL). Non vi è alcun motivo per cui i parametri della query non possano essere RESTful, è solo buona norma utilizzare percorsi in cui i dati possono essere organizzati in gerarchia.
Justin Emery,

5
Le stringhe di query sono perfettamente RESTful purché non si faccia riferimento a risorse in esse. Tendo a pensarli più come filtri che possono modificare il comportamento dell'endpoint.
Sinaesthetic

3
-1, REST è qualcosa di molto specifico, come descritto da Roy Fielding quando l'ha inventato. Vedere questa risposta . in particolare: "Il client deve solo conoscere l'URI iniziale e successivamente scegliere tra le opzioni fornite dal server per navigare o eseguire azioni". . Fondamentalmente, se una qualsiasi parte di un'API documenta endpoint, ad esempio dice "dato un ID utente, è possibile ottenere le informazioni utente su /user/{id}, quindi non è riposante. Considerare: il tuo browser deve venire preprogrammato sapendo come ottenere l'HTML per una domanda stackoverflow pagina?
Claudiu,

1
(continua ...) Che altre persone abusino del termine non cambia ciò che è. Disclaimer, però: sto ancora imparando cos'è REST e questo è ciò che mi ha fatto clic di recente.
Claudiu,

47

In poche parole, REST significa usare HTTP come dovrebbe essere.

Dai un'occhiata alla tesi di Roy Fielding sul REST . Penso che ogni persona che sta facendo lo sviluppo web dovrebbe leggerlo.

Come nota, Roy Fielding è anche uno dei driver chiave dietro il protocollo HTTP.

Per nominare alcuni dei vantaggi:

  • Semplice.
  • Puoi fare buon uso della cache HTTP e del server proxy per aiutarti a gestire un carico elevato.
  • Ti aiuta a organizzare anche un'applicazione molto complessa in risorse semplici.
  • Semplifica l'uso da parte dei nuovi clienti della tua applicazione, anche se non l'hai progettata appositamente per loro (probabilmente perché non erano presenti quando hai creato la tua app).

11
"Semplice": perché REST è più semplice di HTTP?
Dimitri C.

5
"ti aiuta a organizzare": Quindi questa organizzazione è più difficile quando si utilizza semplicemente GET e POST?
Dimitri C.

1
"Semplifica l'utilizzo da parte dei nuovi clienti della tua applicazione": si tratta di REST e semplice HTTP, giusto?
Dimitri C.

23
Conformarsi ai vincoli REST non è sicuramente semplice. Spremere operazioni commerciali complesse in quattro verbi standard è in realtà davvero difficile a volte. Tuttavia, se fatto bene, il risultato finale può essere semplice da capire, ma arrivarci è tutt'altro.
Darrel Miller,

6
@Dimitri: "Semplice" perché ti offre un framework semplice con cui lavorare. REST è HTTP! È molto più semplice di SOAP (che ha anche un nome semplice). "ti aiuta a organizzare" - il concetto non è molto difficile da capire e, una volta implementato correttamente - rende le cose molto bene. REST può essere considerato come un modo di progettare l'app, piuttosto che un dettaglio di implementazione. Come sottolinea Darrel, l'implementazione potrebbe non essere facile, ma il risultato è gratificante. "Rende facile per i nuovi clienti utilizzare l'applicazione" - Ancora una volta: REST è HTTP.
Emil Ivanov,

32

In poche parole: NESSUNO .

Sentiti libero di sottovalutare, ma continuo a pensare che non ci siano benefici reali su HTTP non REST. Tutte le risposte correnti non sono valide. Argomenti della risposta attualmente più votata:

  • Semplice.
  • Puoi fare buon uso della cache HTTP e del server proxy per aiutarti a gestire un carico elevato.
  • Ti aiuta a organizzare anche un'applicazione molto complessa in risorse semplici.
  • Semplifica l'uso da parte dei nuovi clienti della tua applicazione, anche se non l'hai progettata appositamente per loro (probabilmente perché non erano presenti quando hai creato la tua app).

1. Semplice

Con REST hai bisogno di un ulteriore livello di comunicazione per gli script lato server e lato client => in realtà è più complicato dell'uso di HTTP non REST.

2. Memorizzazione nella cache

La memorizzazione nella cache può essere controllata dalle intestazioni HTTP inviate dal server. REST non aggiunge alcuna funzionalità mancante in non REST.

3. Organizzazione

REST non ti aiuta a organizzare le cose. Essa obbliga l'utilizzo di API supportate dalla libreria sul lato server che si sta utilizzando. È possibile organizzare l'applicazione allo stesso modo (o meglio) quando si utilizza un approccio non REST. Ad esempio, vedere Model-View-Controller o routing MVC .

4. Facile da usare / implementare

Per niente vero. Tutto dipende da quanto bene organizzi e documenti la tua candidatura. REST non renderà magicamente migliore la tua applicazione.


3
in genere le API di riposo sono più facili da memorizzare nella cache perché separano i dati in risorse che hanno lo stesso ciclo di vita (vengono creati e aggiornati allo stesso tempo) in modo da poter memorizzare in modo affidabile cache e busting della cache, mentre le API non-riposo spesso restituiscono dati che hanno è stato pesantemente post elaborato o è un conglomerato di più entità che rende più difficile memorizzarlo nella cache
Scott Schulthess,

2
corretto non si escludono a vicenda (è possibile avere un'API di riposo che è memorizzabile nella cache), ma incoraggiare un approccio di riposo alla progettazione dell'API incoraggia e in pratica è sicuramente pertinente in quanto incoraggia varie migliori pratiche (rilevabilità, interfacce generiche, cachability, modellizzazione intelligente delle risorse )
Scott Schulthess il

4
"REST non ti aiuta a organizzare le cose. Ti costringe a utilizzare l'API supportata dalla libreria lato server che stai utilizzando." Non sono sicuro di cosa intendi con questo. È perfettamente possibile (e non è più difficile che costruire un'API non REST) ​​per creare un'API RESTful senza utilizzare un framework lato server aggiuntivo.
Michael O.

2
"Con REST hai bisogno di un ulteriore livello di comunicazione" - humbug, puoi usare bene la tua libreria HTTP esistente.
Søren Boisen,

1
@ SørenBoisen Questa risposta è un po 'vecchia. Probabilmente dovrei aggiornarlo per riflettere maggiormente lo stato attuale delle cose.
Petr Peller,

23

IMHO il vantaggio maggiore che REST consente è quello di ridurre l'accoppiamento client / server. È molto più semplice evolvere nel tempo un'interfaccia REST senza rompere i client esistenti.


4
Potresti fare un esempio? Grazie!
Jan Żankowski,

3
Non dipenderà da quanto è stata sottratta l'API non REST?
johnny,

@johnny È possibile, ma improbabile. I vincoli di REST sono stati scelti per consentire esplicitamente l'evoluzione indipendente dei componenti. Se hai trovato il modo di farlo meglio senza applicare gli stessi vincoli, allora sono sicuro che molte persone vorrebbero saperlo.
Darrel Miller,

@DarrelMiller Potete per favore elaborare in che modo REST riduce l'accoppiamento client / server meglio dell'approccio http Non REST? Credo che tu stia indicando il punto che Timmmm ha detto nella sua risposta. Si prega di vedere il mio ultimo commento sotto la risposta di
Timmmm

I sistemi REST di @emilly non si basano su informazioni fuori banda per poter elaborare la risposta. Non ci sono ipotesi che devono essere fatte su ciò che potrebbe tornare da una particolare richiesta. La risposta ti dice tutto ciò che devi sapere. Ciò consente a un server di modificarne il comportamento e il client può essere a conoscenza di tali modifiche.
Darrel Miller,

15

Discoverability

Ogni risorsa ha riferimenti ad altre risorse, sia nella gerarchia che nei collegamenti, quindi è facile navigare in giro. Questo è un vantaggio per l'essere umano che sviluppa il cliente, salvandolo dalla costante consultazione dei documenti e offrendo suggerimenti. Significa anche che il server può cambiare i nomi delle risorse unilateralmente (purché il software client non esegua l'hardcoding degli URL).

Compatibilità con altri strumenti

Puoi arricciarti in qualsiasi parte dell'API o utilizzare il browser Web per navigare tra le risorse. Semplifica notevolmente il debug e il test dell'integrazione.

Nomi dei verbi standardizzati

Ti permette di specificare le azioni senza dover dare la caccia al testo corretto. Immagina se i getter e i setter di OOP non fossero standardizzati e alcune persone lo usassero retrievee defineinvece. Dovresti memorizzare il verbo corretto per ogni singolo punto di accesso. Sapere che esiste solo una manciata di verbi disponibili per contrastare quel problema.

Stato standardizzato

Se si GETdispone di una risorsa che non esiste, si può essere sicuri di ottenere un 404errore in un'API RESTful. Contrastalo con un'API non RESTful, che può tornare {error: "Not found"}racchiusa in Dio sa quanti strati. Se hai bisogno di spazio extra per scrivere un messaggio allo sviluppatore dall'altra parte, puoi sempre usare il corpo della risposta.

Esempio

Immagina due API con la stessa funzionalità, una dopo REST e l'altra no. Ora immagina i seguenti client per quelle API:

Riposante:

GET /products/1052/reviews
POST /products/1052/reviews       "5 stars"
DELETE /products/1052/reviews/10
GET /products/1052/reviews/10

HTTP:

GET /reviews?product_id=1052
POST /post_review?product_id=1052                  "5 stars"
POST /remove_review?product_id=1052&review_id=10
GET /reviews?product_id=1052&review=10

Ora pensa alle seguenti domande:

  • Se la prima chiamata di ciascun client ha funzionato, quanto puoi essere sicuro che anche il resto funzionerà?

  • È stato apportato un importante aggiornamento all'API che potrebbe aver modificato o meno tali punti di accesso. Quanti documenti dovrai rileggere?

  • Puoi prevedere il ritorno dell'ultima query?

  • Devi modificare la recensione pubblicata (prima di eliminarla). Puoi farlo senza controllare i documenti?


Questo non dovrebbe essere un elenco esaustivo e contiene solo vantaggi molto pratici.
BoppreH,

Questa è una risposta molto intelligente, applaudo.
EralpB,

10

Consiglio di dare un'occhiata a How I Explained REST di Ryan Tomayko a mia moglie

Modifica di terze parti

Estratto dal link waybackmaschine:

Che ne dici di un esempio. Sei un insegnante e vuoi gestire gli studenti:

  • in che classe frequentano,
  • che voti stanno ottenendo,
  • contatti di emergenza,
  • informazioni sui libri a cui insegnate, ecc.

Se i sistemi sono web-based, quindi c'è probabilmente un URL per ognuno dei nomi coinvolti qui: student, teacher, class, book, room, etc. ... Se ci fosse una rappresentazione leggibile dal computer per ciascun URL, sarebbe banale agganciare nuovi strumenti al sistema perché tutte quelle informazioni sarebbero consumabili in modo standard. ... potresti costruire un sistema a livello nazionale in grado di parlare con ciascuno dei singoli sistemi scolastici per raccogliere i punteggi dei test.

Ciascuno dei sistemi otterrebbe informazioni l'uno dall'altro utilizzando un semplice HTTP GET. Se un sistema deve aggiungere qualcosa a un altro sistema, userebbe un POST HTTP. Se un sistema desidera aggiornare qualcosa in un altro sistema, utilizza un HTTP PUT. L'unica cosa che resta da capire è come dovrebbero apparire i dati.


6
Moglie: è un'altra cosa robot?
Tobu

4
Questo è un bel testo, ma non ha fornito alcun esempio del perché sarebbe male usare GET e POST per tutto.
Dimitri C.

9
Ecco perché provo a scoprire perché è meglio :-)
Dimitri C.

7
La scrittura è stata rimossa.
surfato l'


5

Suggerirei a tutti coloro che sono alla ricerca di una risposta a questa domanda di passare attraverso questa "presentazione" .

Non riuscivo a capire cosa fosse REST e perché fosse così bello, i suoi pro e contro, le differenze rispetto a SOAP - ma questa presentazione era così brillante e facile da capire, quindi ora è molto più chiaro per me rispetto a prima.


3

Caching.

Esistono altri vantaggi più approfonditi di REST che ruotano attorno all'abilità evolutiva tramite accoppiamento lento e ipertesto, ma i meccanismi di memorizzazione nella cache sono il motivo principale per cui dovresti preoccuparti di RESTful HTTP.


3
Puoi fare un esempio di cosa potrebbe essere memorizzato nella cache e perché la memorizzazione nella cache non avverrebbe con una soluzione non REST?
Dimitri C.

2
@Dimitri C .: Un link wikipedia.org/article?id=19 non verrebbe memorizzato nella cache da un proxy, poiché ignora i parametri passati nell'URL. D'altra parte un link wikipedia.org/REST verrebbe memorizzato nella cache, capito?
VP.

6
Se la memorizzazione nella cache fosse il principale vantaggio di REST, posso assicurarti che non avrei trascorso gli ultimi due anni a costruire servizi RESTful.
Darrel Miller,

Darrel, potresti creare sistemi su una scala di distribuzione in cui l'accoppiamento libero è della massima importanza (interessato a sapere che tipo di sistemi sono), ma la maggior parte delle persone non lo sono - o stanno usando tecnologie (ad es. browser e html) in cui gran parte del duro lavoro viene svolto per loro.
Mike,

1
Quindi perché non limitarti a utilizzare GET /get_article/19/e POST /update_articlese la memorizzazione nella cache è la tua preoccupazione. È ancora possibile fare tutto con un solo GETed POSTe credo che RESTsignifica "Usa GET, POST, PUTe DELETEsolo." e non solo "Non utilizzare stringhe di query". quindi quello che ho suggerito non sarebbe REST. Inoltre, nessuno può davvero essere d'accordo su ciò che REST è, quindi lo sto mettendo in un secchio con "Web 2.0".
Timmmm,

3

È scritto nella tesi di Fielding . Ma se non vuoi leggere molto:

  • maggiore scalabilità (a causa di vincoli di sistema senza stato, cache e livelli)
  • client e server disaccoppiati (a causa di vincoli di interfaccia stateless e uniformi)
    • client riutilizzabili (il client può utilizzare i browser REST generali e la semantica RDF per decidere quale collegamento seguire e come visualizzare i risultati)
    • client non interrompibili (i client si interrompono solo in base alle modifiche della semantica specifiche dell'applicazione, poiché utilizzano la semantica anziché alcune conoscenze specifiche dell'API)

0
  • Dai a ogni "risorsa" un ID
  • Collega le cose insieme
  • Usa metodi standard
  • Risorse con rappresentazioni multiple
  • Comunicare senza stato

È possibile fare tutto solo con POST e GET? Sì, è l'approccio migliore? No perchè? perché abbiamo metodi standard. Se ci ripensi, sarebbe possibile fare tutto usando solo GET .. quindi perché dovremmo preoccuparci di usare il POST? A causa degli standard!

Ad esempio, oggi pensando a un modello MVC, è possibile limitare l'applicazione affinché risponda solo a tipi specifici di verbi come POST, GET, PUT e DELETE. Anche se sotto il cofano tutto è emulato in POST e GET, non ha senso avere verbi diversi per azioni diverse?


1
"sarebbe possibile fare tutto usando solo GET": ho già fatto alcuni esperimenti con HTTP GET in Silverlight. La mia conclusione è stata che i messaggi GET hanno dimensioni considerevolmente limitate, mentre i messaggi POST possono essere più grandi (di nuovo: nell'impostazione Silverlight). Pertanto sceglierei di utilizzare HTTP POST per tutto! :-)
Dimitri C.

entrambe le soluzioni sono contrarie agli standard. Fare tutto tramite POST non va bene, specialmente per le query. Si noti che negli ultimi anni tutti i motori di ricerca che funzionavano come GET funzionano ora come GET. Perché? perché il metodo "get" ha questa capacità di essere spiderato ...
VP.

0

Il rilevamento è molto più semplice in REST. Abbiamo documenti WADL (simili a WSDL nei servizi Web tradizionali) che ti aiuteranno a pubblicizzare il tuo servizio nel mondo. Puoi anche utilizzare le scoperte UDDI. Con HTTP POST e GET tradizionali, le persone potrebbero non conoscere gli schemi di richiesta messaggi e risposta per chiamarti.


1
Descrivere un servizio Web RESTful con un documento WADL sconfigge uno dei principali vantaggi di REST, in particolare tutti i vantaggi ottenuti dall'ipermedia.
Thomas Eizinger,

@ThomasEizinger Un WADL è davvero una brutta cosa? Attualmente stiamo lavorando con un'altra società che non ha fornito un WADL in cima restituisce oggetti json a seconda di ciò che contiene la nostra richiesta. Presumo che WADL sarebbe utile per chiarire le idee.
surfmuggle,

WADL fa un ottimo lavoro nel descrivere un'API HTTP, perché è per questo che è stato progettato. A seconda del servizio fornito da questa azienda, una WADL può o meno essere una buona idea. Se il servizio non sfrutta l'hypermedia e serializza solo alcuni oggetti in JSON, dovrebbero anche fornire una documentazione (WADL, Swagger, ecc.) Su come funziona il loro servizio e cosa si aspetta / ritorna. WADL di per sé non è affatto male, non è lo strumento giusto per un servizio web (davvero) RESTful.
Thomas Eizinger,

0

Un vantaggio è che, possiamo elaborare in modo non sequenziale documenti XML e dati XML non comuni da diverse fonti come oggetto InputStream, un URL, un nodo DOM ...


0

@Timmmm, sulla tua modifica:

GET /timeline_posts     // could return the N first posts, with links to fetch the next/previous N posts

Ciò ridurrebbe drasticamente il numero di chiamate

E nulla ti impedisce di progettare un server che accetta parametri HTTP per indicare i valori dei campi che i tuoi clienti potrebbero desiderare ...

Ma questo è un dettaglio.

Molto più importante è il fatto che non hai menzionato enormi vantaggi dello stile architettonico REST (scalabilità molto migliore, dovuta all'apolidia del server; disponibilità molto migliore, dovuta anche all'apolidia del server; uso molto migliore dei servizi standard, come la memorizzazione nella cache per esempio, quando si utilizza uno stile architettonico REST; accoppiamento molto più basso tra client e server, a causa dell'uso di un'interfaccia uniforme; ecc. ecc.)

Per quanto riguarda la tua osservazione

"Non tutte le azioni sono facilmente mappabili su CRUD (creare, leggere / recuperare, aggiornare, eliminare)."

: un RDBMS utilizza anche un approccio CRUD (SELECT / INSERT / DELETE / UPDATE) e c'è sempre un modo per rappresentare e agire su un modello di dati.

Per quanto riguarda la tua frase

"Potresti non avere nemmeno a che fare con risorse del tipo di oggetto"

: un design RESTful è, in sostanza, un design semplice - ma questo NON significa che progettarlo sia semplice. Vedi la differenza? Dovrai pensare molto ai concetti che la tua applicazione rappresenterà e gestirà, cosa devi fare, se preferisci, per rappresentarlo tramite risorse. Ma se lo fai, ti ritroverai con un design più semplice ed efficiente.


-1

Le stringhe di query possono essere ignorate dai motori di ricerca.


8
L'uso della stringa di query è totalmente RESTful.
Emil Ivanov,

Dimitri, alcuni motori di ricerca ignorano i collegamenti dinamici. Non più, ma è ancora malvisto. Se gestisci un sito di piccole dimensioni, googlebot potrebbe non indicizzare tutte le tue pagine se presentano un punto interrogativo nel percorso.
malinconico

3
... che è semplicemente falso, quando menzioni Google: googlewebmastercentral.blogspot.com/2008/09/…
Boldewyn,

-1 per le stringhe di query non viene ignorato dai motori di ricerca. webmasters.googleblog.com/2008/09/…
uomo di bronzo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.