3

My web api method should return some structured data about my profile. To do it I created the following POCO classes:

public class ProfileInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    //....

    public ProfileAddress Address { get; set; }
    public ProfileDriverLicense DriverLicense { get; set; }
    public ProfileEmergency Emergency { get; set; }
    public ProfileEmployment Employment { get; set; }
    public ProfileCompensation Compensation { get; set; }
    public ProfileFuel Fuel { get; set; }
    public ProfileCompanyInfo CompanyInfo { get; set; }
}

public class ProfileAddress
{
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

public class ProfileDriverLicense
{
    //....
}

public class ProfileEmergency
{
    //....
}

public class ProfileEmployment
{
    //....
}

public class ProfileCompensation
{
    //....
}

public class ProfileFuel
{
    //....
}

public class ProfileCompanyInfo
{
    //....
}

So, as you can see, there are many POCO classes which nested one to another.

service method, which fills and returns ProfileInfo object:

    public ProfileInfo GetProfile(string username)
    {
        var profile = _db.Drivers.Where(p => p.AspNetUser.UserName == username).Select(k => new ProfileInfo()
        {
            FirstName = k.AspNetUser.FirstName,
            LastName = k.AspNetUser.LastName,
            Username = username,
            Address = new ProfileAddress()
            {
                Address = k.StreetAddress,
                City = k.City,
                State = k.State,
                Zip = k.ZIP
            },
            AvatarUrl = k.AvatarUrl,
            CompanyInfo = new ProfileCompanyInfo()
            {
                //....
            },
            Compensation = new ProfileCompensation()
            {
                //....
            },
            DateOfBirth = k.DOB,
            DriverLicense = new ProfileDriverLicense()
            {
                //....
            },
            Email = k.AspNetUser.UserName,
            Emergency = new ProfileEmergency()
            {
                //....
            },
            Employment = new ProfileEmployment()
            {
                //....
            },
            Fuel = new ProfileFuel()
            {
                //....
            },
            Phone = k.PhoneNo,
            SSN = k.SSN,
            Notes = k.Notes,
            Truck = (k.Truck != null) ? k.Truck.TruckNo : null,
            Trailer = (k.Trailer != null) ? k.Trailer.TrailerNo : null
        }).FirstOrDefault();

        if (profile == null)
            throw new Domain.InvalidDriverException(username);

        return profile;
    }

and WebAPI method:

    [HttpGet]
    [Route("MyProfile")]
    public HttpResponseMessage GetProfile()
    {
        string username = GetUsernameFromClaims();
        if (String.IsNullOrWhiteSpace(username))
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, "User not found");

        var profile = _serviceDriver.GetProfile(username);
        return Request.CreateResponse<Domain.POCO.Profile.ProfileInfo>(profile);
    }

it works and works fine. But any benefits to use POCO classes in concrete this case? Or I can use dynamic and have the same effect, with much less code and no disadvantages? With dynamic I have not to write all these POCO classes and very easy to modify. I understand, that dynamic works much slowly, not easy to find mistake (no compilation errors), but in result Web API returns JSON, which is not strong type by default. What sense to create and use POCO classes?

PS. I use strong types, it's more comfortable for me :) But probably for concrete case I write much extra-code?

user285336
  • 205
  • 3
  • 6
  • 2
    no disadvantages? Really? It's slow; you get no intellisense; no compile-time checking of fields, all fields are read/write (admittedly not a problem in your case as your POCOs are read/write too), which in turn makes it harder to maintain the code as those profile fields can be created, read and written to all over the place as there's no central data structure that defines their contents. Yep, you are right: no disadvantages at all :) – David Arno Mar 21 '18 at 14:50
  • no intellisense - it's not necessary in this case. I write name of field once, when I fill it. no compile-time checking of fields - what sense to checking field names for json? – user285336 Mar 21 '18 at 15:26
  • `With dynamic I have not to write all these POCO classes...` - true, but a stitch in time saves nine. `...and very easy to modify` - I'd disagree. – JᴀʏMᴇᴇ Mar 21 '18 at 15:28
  • @JᴀʏMᴇᴇ why not easy to modify? Just rename name of property in anonymous class, just add any property to anonymous class and don't think about any changes in POCO classes – user285336 Mar 21 '18 at 15:31
  • 1
    Well what do you mean by 'easy'? 'Easy' is subjective. To me, at least, a modification I can do with confidence (because it's typed) is 'easier'. What about consumers of your web service - could it be that you accidentally rename a property? A `dynamic` would cope with this with no problem at all - but the consumer might blow up. That's not easy. It's easier to do what you're saying in the here and now, of course, but a lot of 'sound' programming principles occasionally cost a little bit more time. It's time well spent. EDIT: Not to say there's no place for the use of `dynamic`, there is. – JᴀʏMᴇᴇ Mar 21 '18 at 15:34
  • That's quite a commo missconception. Few developers design thinking in the consumer. They rather focus on the things possible for the API web. It's not till you have to write a web client that you realise how many 'iluminati" are out there developing "APIs". And not just web. – Laiv Mar 21 '18 at 18:24
  • 1
    @user285336: `why not easy to modify?` Maybe easy to modify, but **hard to maintain**. Developers mainly measure code complexity by the difficulty of _figuring out what to change_, as opposed to the actions needed to _make a change_ in something you already understand. Your dynamic approach makes it very hard to figure out what the names of the properties should be. Comparatively, if these property names are available via Intellisense, a developer doesn't need to worry if he made a typo or not, because the compiler will tell him _automatically_ if he used a non-existing property name. – Flater Mar 26 '18 at 15:09
  • 1
    @JᴀʏMᴇᴇ: To extend your point, think of a dynamic which uses the `Color` property. Now hire a British developer who instinctively uses `Colour` (UK spelling). The compiler does not tell him he's wrong, since the compiler doesn't bother to factcheck dynamics. If the British developer had had Intellisense, he would've immediately seen the issue. Without Intellisense, and with a completed build, the developer is now forced to go on a bug hunt because _something_ broke and he doesn't know what. The time cost between the two is immense, and this happens for **every** typo any developer can make. – Flater Mar 26 '18 at 15:14
  • @Flater - I think you explained it much better than I did, to be fair. You're totally right. – JᴀʏMᴇᴇ Mar 27 '18 at 07:57

2 Answers2

4

The advantage of having a strongly-typed return value is that you can have a descriptive document (for example swagger using Swashbuckle) that allows people to auto-generate a client for your API.

If you just return JSON data that is not documented what it looks like, not only do you have to build it dynamically without much error checking on your part, the client will have no way to know how it looks like. So that's trial and error on both sides.

nvoigt
  • 7,271
  • 3
  • 22
  • 26
  • 1
    I don't buy this. It's easy enough to look at the JSON data and construct a DTO for it (or even use it as-is in Javascript, which already deals with it dynamically), assuming that the JSON is consistent. – Robert Harvey Mar 21 '18 at 16:38
  • @RobertHarvey Swagger (or similar things like WSDL for SOAP) are a way to *make sure* the JSON is consistent. How else would you know? Trial and error? – nvoigt Mar 21 '18 at 16:46
  • I'm familiar with WSDL. But that just begs the question: if you're using dynamic binding, you shouldn't require any of those things. Granted, it's a different world, with a different sweet spot. – Robert Harvey Mar 21 '18 at 16:59
  • It's not *required* per se, but I would consider anyone super-unprofessional that says "oh, just call it a few times, you will see what you get". If you have an API endpoint for users, how will you know that a user object can have a car object and a car object can have a color property? You need documentation, everything else is guessing. – nvoigt Mar 21 '18 at 17:09
  • Documentation, yes. But my real-world experience with API's like Twitter and Facebook is that the kind of world you're describing (where everything is standards-based and just works via templates) is pretty rare. Naturally, one should always strive for the ideal, but I wonder how practical that is, given that few seem to achieve it. Professional is as professional does. – Robert Harvey Mar 21 '18 at 17:23
  • Don't know, never worked with the Facebook API, but I randomly clicked around in their API reference and [this](https://developers.facebook.com/docs/graph-api/reference/v2.12/notification) sure looks like a documentation to me. I don't think they created those reference pages by having a herd of interns crawl all their sourcecode in which they build dynamic objects. I'm sure that's somehow generated. – nvoigt Mar 21 '18 at 18:24
  • *"assuming that the JSON is consistent"* . Thus spake weakly typed. QED. – radarbob Mar 21 '18 at 22:36
1

You are right in that there is little advantage to the Strongly typed POCO object in the hosting layer.

In fact, even though I am a proponent of using strong typing, I would be happy to use dynamic over creating new Request/Response type objects which mearly wrap some parameters for the purpose of serialisation.

However! The strong types do serve a purpose in your service layer. ie compile time error checking etc, which is where you construct them.

Additionally, I would expect you to provide a client library to your api, where again, using the same strong types and interface as your service layer has many benefits.

Ewan
  • 70,664
  • 5
  • 76
  • 161