This is an incomplete and changing spec for building models and collections in the new fluent SDK (master branch).
Example service
The example we use to demonstrate the guidelines is Azure Pet store management client. It has a Pets collection which supports all kinds of operations on type Pet.
Pets reside in resource group and have a location property.
Where AutoRest generated types reside?
AutoRest emits the following artifacts to implementation/api directory:
├── implementation/
│ ├── api/
│ │ ├── PetManagementClientImpl.java
│ │ ├── PetsInner.java
│ │ ├── PetInner.java
│ │ ├── Profile.java
Terminology
Top level model : Inner models that represents service request or response payload. In our example PetInner.java is a top level model.
Given below a sample payload to create a Pet entry.
{
"id": 12345
"name": "jacky"
"age": 5
"profile": {
"homeless": true
"weight": 25lb
}
}
Non-top level model : These are usually simple models, the top level model composed of these models. In our example, PetInner.java composes Profile.java.
Where Fluent model and collection types reside?
interfaces
The definition of fluent interfaces for each collection and top level model should reside in the same level as implementation directory.
e.g. Pets.java (fluent collection interface) and Pet.java (fluent model interface)
├── Pets.java
├── Pet.java
├── implementation/
│ ├── api/
│ │ ├── PetManagementClientImpl.java
│ │ ├── PetsInner.java
│ │ ├── PetInner.java
│ │ ├── Profile.java
Note that Profile.java is a non-top level model so there is no fluent model interface for this.
implementations
Implementation for fluent model and collection interfaces should reside under implementation directory.
e.g. PetsImpl.java (fluent collection implementation) and PetImpl.java (fluent model implementation)
├── Pets.java
├── Pet.java
├── implementation/
│ ├── api/
│ │ ├── PetManagementClientImpl.java
│ │ ├── PetsInner.java
│ │ ├── PetInner.java
│ │ ├── Profile.java
│ ├── PetStoreManager.java
│ ├── PetsImpl.java
│ ├── PetImpl.java
Authoring fluent types
- Fluent Models
- Fluent Collections
- Fluent Manager
Fluent models
Pet.java
// public access
public interface Pet
extends GroupableResource {
}
PetImpl.java
// internal accessed impl
class PetImpl implements Pet {
// internal accessed constructor
// takes an inner model and inner collection
PetImpl(PetInner innerModel, PetsInner client, ResourceGroups resourceGroups) {
super(innerModel.id(), innerModel, resourceGroups);
}
/* Some other methods to implement */
@Override
public void refresh() throws CloudException, IOException {
this.setInner(client.get(innerModel.id()));
return this;
}
}
Fluent collections
Pets.java
// public access
public interface Pets extends
SupportsCreating<Pet.DefinitionBlank>,
SupportsListing<Pet>,
SupportsListingByGroup<Pet>,
SupportsGetting<Pet>,
SupportsGettingByGroup<Pet>,
SupportsDeleting,
SupportsDeletingByGroup {
// public access from external will be
public interface InGroup extends
SupportsListing<Pet>,
SupportsGetting<Pet>,
SupportsCreating<Pet.DefinitionWithGroup>,
SupportsDeleting {
}
}
Pets interface represents the operations that can be performed on the Pets collection across all resource groups in the service.
Pets.InGroup represents the operations that can be performed on the Pets collection in a specific resource group.
Since the most common operations that can be performed on a collection are CRUD, these operations are extracted out as runtime interfaces. The fluent collection interface extends from these runtime interfaces. Refer the section Runtime CRUD interfaces for details.
PetsImpl.java
// internal accessed class
final class PetsImpl implements Pets {
// internal constructor
PetsImpl(PetsInner client, ResourceGroups resourceGroups) {
}
// Implementation of CRUD interfaces
....
}
PetsInGroupImpl.java
// internal accessed class
final class PetsInGroupImpl implements Pets.InGroup {
// internal constructor
PetsInGroupImpl(Pets pets, ResourceGroup resourceGroup) {
}
// implementation of Group-level CRUD interfaces
....
}
Fluent manager
Manager serve as a container for all fluent collections associated with a service. Each manager will have 3 static methods that consumers can use to authenticate and get an instance of manager.
public final class PetStoreManager {
// authenticate with configuration
public static Configurable configurable() {
return new PetStoreManager().new ConfigurableImpl(); }
}
// authenticate with default configuration
public static PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId) {
return new PetStoreManager(credentials, subscriptionId);
}
// authenticate using pre-configured RestClient
public static PetStoreManager authenticate(RestClient restClient, String subscriptionId) {
return new PetStoreManager(restClient, subscriptionId);
}
public interface Configurable extends AzureConfigurable<Configurable> {
PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId);
}
final class ConfigurableImpl extends AzureConfigurableImpl<Configurable> implements Configurable {
public PetStoreManager authenticate(ServiceClientCredentials credentials, String subscriptionId) {
buildRestClient(credentials);
return PetStoreManager.authenticate(restClient, subscriptionId);
}
}
// PetStoreManager constructors
....
// The fluent collection getters
public Pets pets() {
...
}
}
Runtime CRUD interfaces
Each fluent collection interface (e.g. Pets.java) should expose methods that allows users to perform C (Create), R (Read), U (Update) and D (Delete) operations on the collection. Exposing one of these method depends on whether service supports corresponding operation or not.
Create interface
public interface SupportsCreating<T> {
T define(String name) throws Exception;
}
Read interfaces
public interface SupportsListing<T> {
PagedList<T> list() throws CloudException, IOException;
}
public interface SupportsGetting<T> {
T get(String name) throws CloudException, IOException;
}
public interface SupportsListingByGroup<T> {
PagedList<T> list(String groupName) throws CloudException, IOException;
}
public interface SupportsGettingByGroup<T> {
T get(String groupName, String name) throws CloudException, IOException;
}
Update interface
public interface SupportsUpdating<T> {
T update(String name);
}
Delete interface
public interface SupportsDeleting {
void delete(String id) throws Exception;
}
public interface SupportsDeletingByGroup {
void delete(String groupName, String name) throws Exception;
}
Example
This is an incomplete and changing spec for building models and collections in the new fluent SDK (
masterbranch).Example service
The example we use to demonstrate the guidelines is Azure Pet store management client. It has a
Petscollection which supports all kinds of operations on typePet.Pets reside in resource group and have a location property.
Where AutoRest generated types reside?
AutoRest emits the following artifacts to
implementation/apidirectory:Terminology
Top level model : Inner models that represents service request or response payload. In our example
PetInner.javais a top level model.Given below a sample payload to create a Pet entry.
{ "id": 12345 "name": "jacky" "age": 5 "profile": { "homeless": true "weight": 25lb } }Non-top level model : These are usually simple models, the top level model composed of these models. In our example,
PetInner.javacomposesProfile.java.Where Fluent model and collection types reside?
interfaces
The definition of fluent
interfacesfor each collection and top level model should reside in the same level asimplementationdirectory.e.g.
Pets.java(fluent collection interface) andPet.java(fluent model interface)Note that
Profile.javais a non-top level model so there is no fluent model interface for this.implementations
Implementation for fluent model and collection interfaces should reside under
implementationdirectory.e.g.
PetsImpl.java(fluent collection implementation) andPetImpl.java(fluent model implementation)Authoring fluent types
Fluent models
Pet.java
PetImpl.java
Fluent collections
Pets.java
Petsinterface represents the operations that can be performed on the Pets collection across all resource groups in the service.Pets.InGrouprepresents the operations that can be performed on the Pets collection in a specific resource group.Since the most common operations that can be performed on a collection are CRUD, these operations are extracted out as runtime interfaces. The fluent collection interface extends from these runtime interfaces. Refer the section Runtime CRUD interfaces for details.
PetsImpl.java
PetsInGroupImpl.java
Fluent manager
Manager serve as a container for all fluent collections associated with a service. Each manager will have 3 static methods that consumers can use to
authenticateand get an instance of manager.Runtime CRUD interfaces
Each fluent collection interface (e.g.
Pets.java) should expose methods that allows users to perform C (Create), R (Read), U (Update) and D (Delete) operations on the collection. Exposing one of these method depends on whether service supports corresponding operation or not.Create interface
Read interfaces
Update interface
Delete interface
Example