Skip to content

Auto-gen ViewModels from ApiController #1

@spelltwister

Description

@spelltwister

It would be amazing to be able to generate view models based on ApiControllers. Here is what I mean:

[RoutePrefix("api/person")]
public class PersonApiContoller : ApiContoller{
    [Route("")]
    [HttpGet]
    public async Task<Person[]> GetAll(){
        return await dbContext.People.ToListAsync();
    }

    [Route("create")]
    [HttpPost]
    public async Task<Guid> CreatePerson(CreatePersonRequest toCreate){
        Guid ret = Guid.NewGuid();
        dbContext.People.Add(new Person(){ Id  =ret, FirstName=  toCreate.FirstName, DateOfBirth = toCreate.DateOfBirth});
        await dbContext.SaveChangesAsync();
        return ret;
    }
}

public class CreatePersonRequest
{
    public string FirstName{get;set;}
    public DateTime DateOfBirth {get;set;}
}

public class Person
{
    public Guid Id {get;set;}
    public string FirstName{get;set;}
    public DateTime DateOfBirth{get;set;}
}

======= GENERATES ==========

class PersonViewModel {
    private urlBase: string;
    constructor(urlBase: string){
        this.urlBase = urlBase + "/api/person";// found from the RoutePrefix attribute
    }

    GetAll() : JQueryPromise<Person[]>{
       // HttpGet attribute means we can use $.getJSON
       $.getJSON(this.urlBase + ""/*found from the Route attribute*/);  
    }

    CreatePerson(person: CreatePersonRequest) : JQueryPromise<string/*aka, GUID*/> {
        // HttpPost attribute means we need to use $.post
        return $.post(this.urlBase + "/create"/*found from the Route attribute*/, ko.toJS(person));
     }
}

// Return type from the API
// Preferred over interface
type Person = {
    Id: string; // aka, GUID
    FirstName: string;
    DateOfBirth: Date;
}

// may or may not want to generate an edit version
class PersonEdit {
   Id: string; // not observable
   FirstName: KnockoutObservable<string>; // perferred over FirstName(): string;  KnockoutObservable is more than just a function
   DateOfBirth: KnockoutObservable<Date>;

   constructor(initial?:Person){
       this.Id = initial && initial.Id;
       this.FirstName = ko.observable(initial && initial.FirstName);
       this.DateOfBirth = ko.observable(initial && initial.DateOfBirth);
    }
}

// input type should be observable
class CreatePersonRequest {
    FirstName: KnockoutObservable<string>;
    DateOfBirth: KnockoutObservable<Date>;

    constructor(initial?:Person){
       this.FirstName = ko.observable(initial && initial.FirstName);
       this.DateOfBirth = ko.observable(initial && initial.DateOfBirth);
    }
}

====== USAGE =======

// typically extend view model to add client side stuff
// could also compose a view model from multiple generated view models
class MyPersonViewModel extends PersonViewModel {
    CustomerList: KnockoutObservableArray<Person>;
    ActiveCustomer: KnockoutObservable<Person>;
    EditCustomer: KnockoutComputed<EditPerson>;

    constructor(urlBase: string){
       super(urlBase);

       this.CustomerList = ko.observableArray();
       this.ActiveCustomer = ko.observable(null);
       this.EditCustomer = ko.pureComputed((newVal) => {
           return newVal && new EditPerson(newVal);
       });
    }

    LoadCustomerList() : void {
       this.GetAll().then((list) => this.CustomerList(list));
    }

    SelectCustomer(customer: Person) : void {
       this.ActiveCustomer(customer);
    }

    SaveCustomer() : JQueryPromise<string> {
        if(!this.ActiveCustomer()){
             throw 'No Customer Selected.';
        }
        return this.CreatePerson(new CreatePersonRequest(ko.toJS(this.ActiveCustomer()));
    }
}

@section scripts{
   <script>
       var vm = new MyPersonViewModel ('@Url.Content("~/")');
       $(function(){
            vm.LoadCustomerList();
            ko.applyBindings(vm);
         });
   </script>
}

I would gladly do the work if you could help me understand the project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions