Modellazione dei Dati
Goa fornisce un potente sistema di tipi che ti permette di modellare il tuo dominio con precisione e chiarezza. Dai primitivi semplici alle strutture nidificate complesse, il DSL offre un modo naturale per esprimere relazioni tra dati, vincoli e regole di validazione.
Tipi Base
La fondazione del sistema di tipi di Goa inizia con i tipi primitivi e le definizioni di tipo base. Questi blocchi di costruzione ti permettono di creare strutture dati semplici ma espressive.
Tipi Primitivi
Goa fornisce un ricco set di tipi primitivi integrati che servono come fondamento per tutta la modellazione dei dati:
Boolean // booleano JSON
Int // intero con segno
Int32 // intero con segno a 32 bit
Int64 // intero con segno a 64 bit
UInt // intero senza segno
UInt32 // intero senza segno a 32 bit
UInt64 // intero senza segno a 64 bit
Float32 // numero in virgola mobile a 32 bit
Float64 // numero in virgola mobile a 64 bit
String // stringa JSON
Bytes // dati binari
Any // valore JSON arbitrario
Definizione di Tipo
La funzione DSL Type è il modo principale per definire tipi di dati strutturati. Supporta attributi, validazioni e documentazione:
var Person = Type("Person", func() {
Description("Una persona")
// Attributo base
Attribute("name", String)
// Attributo con validazione
Attribute("age", Int32, func() {
Minimum(0)
Maximum(120)
})
// Campi obbligatori
Required("name", "age")
})
Tipi Complessi
Quando si modellano domini del mondo reale, spesso si necessita di strutture dati più sofisticate. Goa fornisce un supporto completo per collezioni e tipi nidificati.
Array
Gli array ti permettono di definire collezioni ordinate di qualsiasi tipo, con regole di validazione opzionali:
var Names = ArrayOf(String, func() {
// Valida elementi dell'array
MinLength(1)
MaxLength(10)
})
var Team = Type("Team", func() {
Attribute("members", ArrayOf(Person))
})
Mappe
Le mappe forniscono associazioni chiave-valore con type safety e validazione sia per le chiavi che per i valori:
var Config = MapOf(String, Int32, func() {
// Validazione chiave
Key(func() {
Pattern("^[a-z]+$")
})
// Validazione valore
Elem(func() {
Minimum(0)
})
})
Composizione dei Tipi
Goa supporta pattern sofisticati di composizione dei tipi che abilitano il riuso del codice e una chiara separazione delle responsabilità.
Reference
Usa Reference per impostare proprietà predefinite per gli attributi da un altro tipo. Quando un attributo nel tipo corrente ha lo stesso nome di uno nel tipo referenziato, eredita le proprietà dell’attributo referenziato. Possono essere specificate multiple reference, con le proprietà cercate nell’ordine di apparizione:
var Employee = Type("Employee", func() {
// Riusa definizioni di attributi da Person
Reference(Person)
Attribute("name") // Non serve definire l'attributo name di nuovo
Attribute("age") // Non serve definire l'attributo age di nuovo
// Aggiungi nuovi attributi
Attribute("employeeID", String, func() {
Format(FormatUUID)
})
})
Extend
Extend crea un nuovo tipo basato su uno esistente, perfetto per modellare
relazioni gerarchiche. A differenza di Reference, Extend eredita automaticamente
tutti gli attributi dal tipo base.
var Manager = Type("Manager", func() {
// Estendi tipo base
Extend(Employee)
// Aggiungi campi specifici del manager
Attribute("reports", ArrayOf(Employee))
})
Regole di Validazione
Goa fornisce capacità di validazione complete per assicurare l’integrità dei dati e applicare regole di business: Ecco le regole di validazione chiave disponibili in Goa:
Validazioni String
Pattern(regex)- Valida contro un’espressione regolareMinLength(n)- Lunghezza minima stringaMaxLength(n)- Lunghezza massima stringaFormat(format)- Valida contro formati predefiniti (email, URI, ecc)
Validazioni Numeriche
Minimum(n)- Valore minimo (inclusivo)Maximum(n)- Valore massimo (inclusivo)ExclusiveMinimum(n)- Valore minimo (esclusivo)ExclusiveMaximum(n)- Valore massimo (esclusivo)
Validazioni Array e Mappe
MinLength(n)- Numero minimo di elementiMaxLength(n)- Numero massimo di elementi
Validazioni Oggetti
Required("field1", "field2")- Campi obbligatori
Validazioni Generiche
Enum(value1, value2)- Restringe a valori enumerati
Inoltre gli elementi di array e mappe possono essere validati usando le stesse regole degli attributi.
Le regole di validazione possono essere combinate per creare logica di validazione completa:
var UserProfile = Type("UserProfile", func() {
Attribute("username", String, func() {
Pattern("^[a-z0-9]+$") // Pattern regex
MinLength(3) // Lunghezza minima stringa
MaxLength(50) // Lunghezza massima stringa
})
Attribute("email", String, func() {
Format(FormatEmail) // Formato integrato
})
Attribute("age", Int32, func() {
Minimum(18) // Valore minimo
ExclusiveMaximum(150) // Valore massimo esclusivo
})
Attribute("tags", ArrayOf(String, func() { Enum("tag1", "tag2", "tag3") }), func() {
// Valori enum per elementi array
MinLength(1) // Lunghezza minima array
MaxLength(10) // Lunghezza massima array
})
Attribute("settings", MapOf(String, String), func() {
MaxLength(20) // Lunghezza massima mappa
})
Required("username", "email", "age") // Campi obbligatori
})
Tipi Personalizzati
Crea tipi personalizzati riutilizzabili per incapsulare formati specifici del dominio e regole di validazione:
// Definisci formato personalizzato
var UUID = Type("UUID", String, func() {
Format(FormatUUID)
Description("UUID RFC 4122")
})
// Usa tipo personalizzato
var Resource = Type("Resource", func() {
Attribute("id", UUID)
Attribute("name", String)
})
Vedi il DSL Type per maggiori dettagli.
Formati Integrati
Goa include un set completo di formati predefiniti per pattern di dati comuni. Questi formati forniscono validazione automatica e chiaro significato semantico:
FormatDate- valori data RFC3339FormatDateTime- valori data e ora RFC3339FormatUUID- valori UUID RFC4122FormatEmail- indirizzi email RFC5322FormatHostname- nomi host Internet RFC1035FormatIPv4- valori indirizzo IPv4 RFC2373FormatIPv6- valori indirizzo IPv6 RFC2373FormatIP- valori indirizzo IPv4 o IPv6 RFC2373FormatURI- valori URI RFC3986FormatMAC- valori indirizzo MAC IEEE 802 MAC-48, EUI-48 o EUI-64FormatCIDR- valori indirizzo IP in notazione CIDR RFC4632 e RFC4291FormatRegexp- sintassi espressione regolare accettata da RE2FormatJSON- testo JSONFormatRFC1123- valori data e ora RFC1123
DSL Attribute vs Field
Goa fornisce due modi equivalenti per definire attributi di tipo: Attribute e Field. La differenza principale è che Field prende un parametro tag aggiuntivo che viene usato per i numeri di campo dei messaggi gRPC.
DSL Attribute
Usato quando non hai bisogno del supporto gRPC o quando definisci tipi che non saranno usati nei messaggi gRPC:
var Person = Type("Person", func() {
Attribute("name", String)
Attribute("age", Int32)
})
DSL Field
Usato quando si definiscono tipi che saranno usati nei messaggi gRPC. Il primo argomento è il tag numero di campo:
var Person = Type("Person", func() {
Field(1, "name", String)
Field(2, "age", Int32)
})