Skip to content

Commit 49a3451

Browse files
committed
Add coding guidelines (WIP)
Signed-off-by: Dainius Serplis <dserplis@vmware.com>
1 parent a4f7310 commit 49a3451

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

CODING_GUIDELINES.md

+115
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,122 @@ the request header.
475475

476476
When the tenant context is not needed (system administration calls), we just pass `nil` as `additionalHeader`.
477477

478+
## Generic CRUD functions for OpenAPI entity implementation
478479

480+
Generic CRUD functions are used to minimize boilerplate for entity implementation in the SDK.
481+
482+
### Terminology
483+
484+
#### inner vs outer types
485+
486+
For the context of generic CRUD function implementation (mainly in files
487+
`govcd/openapi_generic_outer_entities.go`, `govcd/openapi_generic_inner_entities.go`), such terms
488+
are commonly used:
489+
490+
* `inner` type is the type that is responsible for marshaling/unmarshaling API
491+
request payload and is usually inside `types` package. (e.g. `types.IpSpace`,
492+
`types.NsxtAlbPoolMember`, etc.)
493+
* `outer` (type) - this is the type that wraps `inner` type and possibly any other entities that are
494+
required to perform operations for a particular VCD entity. It will almost always include some
495+
reference to client (`VCDClient` or `Client`), which is required to perform API operations. It may
496+
contain additional fields.
497+
498+
Here are the entities mapped in the example below:
499+
500+
* `DistributedFirewall` is the **`outer`** type
501+
* `types.DistributedFirewallRules` is the **`inner`** type (specified in
502+
`DistributedFirewall.DistributedFirewallRuleContainer` field)
503+
* `client` field contains the client that is required for perfoming API operations
504+
* `VdcGroup` field contains additional data (VDC Group reference) that is required for
505+
implementation of this particular entity
506+
507+
```go
508+
type DistributedFirewall struct {
509+
DistributedFirewallRuleContainer *types.DistributedFirewallRules
510+
client *Client
511+
VdcGroup *VdcGroup
512+
}
513+
```
514+
515+
#### crudConfig
516+
517+
A special type `govcd.crudConfig` is used for passing configuration to both - `inner` and `outer`
518+
generic CRUD functions. It also has an internal `validate()` method, which is called upon execution
519+
of any `inner` and `outer` CRUD functions.
520+
521+
### Use cases
522+
523+
The main consideration when to use which functions depends on whether one is dealing with `inner`
524+
types or `outer` types. Both types can be used for quicker development.
525+
526+
Usually, `outer` type is used for a full featured entity (e.g. `IpSpace`, `NsxtEdgeGateway`), while
527+
`inner` suits cases where one needs to perform operations on an already existing entity.
528+
529+
**Hint:** return value of your entity method will always hint whether it is `inner` or `outer` one:
530+
531+
`inner` type function signature example (returns `*types.VdcNetworkProfile`):
532+
533+
```
534+
func (adminVdc *AdminVdc) UpdateVdcNetworkProfile(vdcNetworkProfileConfig *types.VdcNetworkProfile) (*types.VdcNetworkProfile, error) {
535+
```
536+
537+
`outer` type function signature example (returns `*IpSpace`):
538+
539+
```
540+
func (vcdClient *VCDClient) CreateIpSpace(ipSpaceConfig *types.IpSpace) (*IpSpace, error) {
541+
```
542+
543+
544+
#### Use cases for inner types
545+
546+
Inner types are more simple as they can be directly used without any additional overhead. There are
547+
5 functions that can be used:
548+
549+
* `createInnerEntity`
550+
* `updateInnerEntity`
551+
* `getInnerEntity`
552+
* `deleteEntityById`
553+
* `getAllInnerEntities`
554+
555+
Such entities are usually one of:
556+
* API property manipulation with separate API endpoints for an already existing entity (e.g. VDC
557+
Networ Profiles `Vdc.UpdateVdcNetworkProfile`)
558+
* Read only entities (e.g. NSX-T Segment Profiles `VCDClient.GetAllIpDiscoveryProfiles`)
559+
560+
Existing examples of the implementation are:
561+
* `Vdc.GetVdcNetworkProfile`
562+
* `Vdc.UpdateVdcNetworkProfile`
563+
* `Vdc.DeleteVdcNetworkProfile`
564+
* `VCDClient.GetAllIpDiscoveryProfiles`
565+
566+
567+
#### Use cases for outer types
568+
569+
Any `outer` type *must* implement `wrap` method as per signature below. It is required to satisfy
570+
generic interface constraint (so that generic functions are able to wrap `inner` type into `outer`
571+
type)
572+
573+
```go
574+
func (o OuterEntity) wrap(inner *InnerEntity) *OuterEntity {
575+
o.OuterEntity = inner
576+
return &o
577+
}
578+
```
579+
There are 4 functions for handling CRU(D).
580+
* `createOuterEntity`
581+
* `updateOuterEntity`
582+
* `getOuterEntity`
583+
* `getAllOuterEntities`
584+
585+
*Note*: `D` (deletion) in `CRUD` is a simple operation that does not additionally handle data and
586+
`deleteEntityById` is sufficient.
587+
588+
Existing examples of the implementation are:
589+
* `IpSpace`
590+
* `IpSpaceUplink`
591+
* `DistributedFirewall`
592+
* `DistributedFirewallRule`
593+
* `NsxtSegmentProfileTemplate`
479594

480595
## Testing
481596

0 commit comments

Comments
 (0)