11

So, somebody at work who is twice as experienced than I am, told us that we must not create ViewModel classes within Web API. (We are using Angular for UI)

In his opinion ViewModel is ASP.NET MVC approach. And we must come out of it when using Web API.

Here is my argument for using ViewModel in WebAPIs:

Database Tables

Employee

name | phone | categoryId |...Col15

Category

categoryId | Description

C# Class

Class Employee
{
 public string name {get;set;}
 public phone {get;set;}
 public categoryId {get;set;}
 //...till col15
}

If your UI page shows only :

 name | phone | categoryId | CategoryDescription

Wouldn't it make sense to create a ViewModel class in API that has only these 4 properties as opposed to all 15 properties? The JSON that will be returned by this class will only have 4 properties instead of 15 properties where 11 of them contain null value.

If there is a list of say 100 Employees it would mean 1100 empty json properties that will be sent to the UI if we use original Employee class instead of a ViewModel class.

Also, if we stick to our original Employee class we might have to do one of the following:

  1. CategoryDescription must be added to original Employee class
  2. Make a second API call from UI to get the description.
3
  • 9
    It's fine and good, just don't call it view models. Call them resource models or something like that, and everyone will be happy.
    – JacquesB
    Oct 11, 2019 at 9:27
  • 2
    Or DTOs.
    – John Wu
    Oct 15, 2019 at 8:50
  • 1
    A funny distinction by your colleague between WebAPI-approach and MVC-approach; considering that Microsoft merged the two concepts years ago - and for good reason.
    – nicholas
    Nov 4, 2021 at 14:56

5 Answers 5

10

You’ve asked two questions here and I think things will make more sense with a deeper dive into API architecture. The first thing I will say is than an API should ALWAYS have an independent ViewModel as the request/response data objects. I’ll address that in more in question 2.

ViewModel: A data model passed between an external entity and the presentation layer of a web application. APIs are a web application with a presentation layer, therefore, they have ViewModels though we call them several different things (contracts, requests, responses, etc). (Human (entity) -> web page (presentation layer)) (App (entity) -> Api Controller (presentation layer))

You can think of ViewModels more as a role than a naming convention in regards to APIs; you might be use to seeing these data vehicles called by another name. As long as they're there, all is well.

  • Does it make sense to pass back from the API only the fields our view will use? No – this is assigning the wrong responsibility to the API. API’s expose units of business logic therefore what we need to return is the business process data, not the data needed for a specific page’s view model. It’s the job of your site’s adapter to map the business model to your page’s ViewModel. Now, it might happen to be that your business model and view model are identical, but that’s coincidence, not design. The API should have no knowledge of what the web page needs to render, that’s the website’s responsibility. If a process needs to return more data than the page will use, so be it.

  • Should an API use ViewModels? YES! Always! A well-designed API will have at least 3 layers: Presentation (Api layer, UI layer), Core (sometimes called application, business or/and domain), and Infrastructure (sometimes called data or service layer) The Presentation layer will have ViewModels, the Core layer will have your business models, and the Infrastructure layer will have DTOs and external service ViewModels/Contracts. You will have adapters (aka mappers) that transform these objects into one another. There are two big reasons for this (among any others); most important is security and mutability.

  • ViewModels & Security: As a security principal you should never return your business object nor your data object through a presentation layer. Most often we have data in those objects for operation that doesn’t need to be exposed. Rule of thumb is to return as little data as possible. Additionally, our business layer often needs access to raw data but the presentation layer should only expose scrubbed data. Take a credit card number for example. The business layer operates on the full number, but the presentation layer returns a number xxxxx4856 masked. If your consuming apps never needs the full #, never pass it in the first place as a defensive design.

  • ViewModels & Mutability: Another reason to build your API with the extra models/adapters is mutability. We want to build our API with as much Separation of Concern as possible. Here is an example. Let’s say we return card data. We learn to we’re not allowed by law to display, store, or operate on the card number and the CVV together so we decide to remove CVV from being returned from the API. Uh oh – we were returning our business model as the response to the call. Now we must change a business model which affects the Core layer logic and the Presentation layer logic – gross. If we use a ViewModel to begin with, we simply do not return the CVV in the ViewModel, the Core remains unchanged and happy.

There are three key things to think about when developing an API, even one used as a lean standalone operation layer for a website (doesn’t model business rules).

  1. Separation of Concerns
  2. Ports and Adapter Pattern
  3. Formal API Architecture – I personally like the Clean Architecture for learning and it has strong testability and mutability. I highly recommend you learn a strong API Architecture as it’ll resolve a lot of questions for you as you start to understand areas of responsibility in your API and why. Again, I’m a big fan of learning Clean Architecture simply because there's so much to learn from it. (Its also highly recommended by Microsoft.) It is over kill for several applications, but the learning is priceless. (Presentation/Core/Infrastructure naming convention of the layers I referenced is a Clean Architecture convention.) Feel free to explore others; Hexagonal, Onion, N-Tier, etc etc. I’ll leave you to Google for that.
5
  • 3
    Nice answer! At least somebody understands it. I am getting tired of CRUD APIs wrongly called REST serving the database directly to the client with anemic domain models. :S
    – inf3rno
    May 24, 2022 at 0:40
  • 1
    If you have anemic domain models, I would argue that you do not have domain models at all. Domain models are the entity in its entirety and that definition is non-mutable. This is why business models (including domains if doing DDD) are often quite larger than the viewmodels/contracts being returned. You might pass a VM that mimics the domain back as a response from an API call depending on where your API sits, but it's not unusual that responses include a subset or mutation of a domain model - thus why VMs exist.
    – Hope
    Sep 5, 2023 at 2:08
  • @Hope, I was wondering if you could recommend a book or online resource that explains Clean Architecture from the ground up. I have been trying for years to fully understand DDD and implement it correctly but there are too many differing opinions and variations online. The usage of multiple terms for the same thing (i.e. domain, core, business, app) makes it harder to follow. For me the holy grail is a single definitive implementation of DDD and repository pattern that works for any project.
    – LNX
    Jan 24 at 15:34
  • @LNX Sure! Apologies on seeing this so late. Clean Architecture is based on dozens of principals and patterns, which makes learning it as a topic itself a bit like a fire hose. Get a base understanding in each and it goes easier! The two most important aspects in my career was Ports and Adapter's pattern and frankly the naming convention. For DDD, I really like Dometrain's course on it. Its large, but you can see how Scrum and DDD go hand & hand. As for learning CA, I'd get grounded in its parts first, then go learn CA. I'll post a list when I can find one worth sharing.
    – Hope
    Mar 11 at 10:58
  • @LNX CA expects you to already understand the principals & patterns, CA just shows you how to make them work in harmony. Finding the break down is hard. Dometrain has a CA that's decent. Matthew Renze's CA is loved but I've not vetted. Amichai Mantinband has a youtube series. For patterns start with: Ports & Adapters, CQRS, Mediator, Results, Repository, Facade, Factory, and Unit of Work. CA has 1 defined terminology to call assets. That's its point & TBH that's its biggest win. When sources deviate from that naming conv. be hesitant to trust them. Uncle Bob created CA, follow his naming.
    – Hope
    Mar 11 at 11:34
5

What you are doing is fine. You should expose only the data which is necessary for the clients.

Just don't call it "view models" since this term have a specific meaning in the context of user interfaces and will create confusion when used outside of this context. Call it "Data Transfer Objects" and everyone will be happy.

It is not a good idea to expose entities directly through an API. This creates a tight coupling which means any minor change in the business logic will cause breaking changes in the API (and vice versa). You want to avoid that.

4

In principle, frontend frameworks such as Angular are best used against a REST API, which implies that you don't have viewmodels and simply expose your resources as they are.

However, from the sound of it, you're not using a REST API but rather an API tailored to the needs of the frontend application. I say this because you mention that the API specifically omits 11 out of 15 properties because it knows that the frontend won't need them for this particular case.

If that is the case, then your API is inherently aware of your frontend application views, and you are effectively working with viewmodels. It seems like your colleague is simply suggesting to not make an explicit viewmodel and instead is trying to reuse existing DTOs but with properties that are intentionally kept empty, which is not good practice.

So, to summarize, the "no viewmodels" stance works if you have a REST API. If you have an API which handles custom requests and automatically redacts data because it knows what the frontend will/won't display, then the "no viewmodels" stance is contradictory to how the API is being developed.


Additionally:

In his opinion ViewModel is ASP.NET MVC approach.

MVC stands for Model-View-Controller. MVC has no viewmodels. MVVM (Model-View-ViewModel) however does have viewmodels.

I'm not sure whether this conflation is on your side or on your colleague's side, but it's nigh impossible to productively discuss the use of viewmodels (or lack thereof) if either party can't distinguish MVC and MVVM.
At the very least, you'd be using the wrong name (viewmodel vs model), which makes it really hard for other people to provide accurate feedback based on your explanation.

7
  • 2
    I'm on the fence about this answer. The "view model" concept is something only the server application cares about. You don't necessarily want to expose the entire resource in your REST API due to security concerns, and especially since you don't want badly/maliciously crafted requests to result in business rule violations. A REST API is not simply CRUD operations on a table in the database. It still must go through business rules and constraints, but "act" like a resource to the outside world. Oct 9, 2019 at 17:28
  • 1
    @GregBurghardt: I didn't mean to imply that you must expose the whole entity. What I meant is that in a pure REST API, the resource is exposed the way it is intended to be exposed, regardless of which (partial) view the information is going to be being displayed in. Effectively, the backend doesn't know what specific (partial) view the data is going to be used in. But I guess this is open to subjectivity, one man's resource with redacted properties is another man's (view)model I suppose. In the end it's all about DTOs.
    – Flater
    Oct 9, 2019 at 17:30
  • I understand that if we are developing a generic REST API for 20 clients whose needs might defer then it would make sense to expose DTOs instead of creating methods and ViewModels to suit each of the 20 clients. But if we are developing an API for just one or two clients. we would be better off creating ViewModels. Am I correct? Oct 9, 2019 at 17:39
  • 3
    @SamuraiJack: Not particularly. It's a matter of approach. A REST API can make sense for a low number of consumers too. A REST API is generally more loosely coupled to its frontend. When the frontend and backend devs are in different teams, it requires less coordination between the two. It also allows for simpler changes since the BE doesn't need to be changed when the FE adds/removes a display field. But a more tightly coupled API can save more on calls/performance when written well. Either can work, either has its advantages.
    – Flater
    Oct 9, 2019 at 19:35
  • 1
    @nicholas: To use an example, a viewmodel (MVVM) would track if you have opened/collapsed an accordion in the UI. A model (MVC) doesn't care about those things; it only cares about what data is being passed from the controller to the view. The state of the view is managed in the view, from the perspective of MVC, it is not contained in the model.
    – Flater
    Jan 21 at 23:08
2

Yes it is bad practice.

Essentially you are moving logic from your javascript client application to the server side.

This works well when you are making page requests with little or no client side logic, but not when you have a single page app where all of the presentation logic at least is supposed to be client side to take advantage of the various benefits that can bring.

So in your first example, if you create the EmployeeViewModel with cut down fields, but then later need one of those fields on the front end, you now have to edit both front and back end.

in your second example where you enrich the employee with the category description, your client is quite capable of requesting the information separately, holding it in memory and joining it to employees, using it in drop downs etc etc

In each case adding a view model to the server reduces the flexibility and available options in your client side code

6
  • I agree that introducing ViewModels would mean making changes to both client and server end but wouldn't ViewModels mean better performance? We could save multiple calls to the server. Oct 11, 2019 at 17:42
  • @SamuraiJack: I would measure a performance problem first before using view models in a web API. In fact, I would verify first that the performance of not using view models is, in fact, unacceptable to end users. Just defaulting to view models in a web API might be premature optimization. Oct 11, 2019 at 18:52
  • If the project is finished, then you could go through and optimise to reduce the number of calls. But this comes at the cost of reducing your flexibility going forward. Also reducing the number of calls does not necessarily improve performance overall
    – Ewan
    Oct 14, 2019 at 8:03
  • @SamuraiJack: to build on what Ewan said in his last comment, you really need to know where the performance bottleneck exists first. You can spend a lot of time and money refactoring your API responses to only realize you need to paginate data, rather than fiddle with the data structure, because the client cannot handle that much data at once. Raw HTTP responses should be at least compressed with GZIP compression (or something similar). That is a much more efficient means of reducing network time. Oct 22, 2019 at 11:06
  • Depending on what that logic is, you want that on the server side. There's security to be had there. In the regulated industries we're not allowed to put certain logics on the client side, it violates auditing and regulations. Performance is the least of your worries.
    – Hope
    Sep 5, 2023 at 2:13
0

According to me, if you are using a repository pattern in your Web API project then in that case, it is good practice to use view model for the direct interaction with the database from front end side. In other cases, you can do operations without using view models.

Not the answer you're looking for? Browse other questions tagged or ask your own question.