I have a method definition:
public async Task<IHttpActionResult> FindUsers([FromBody]User user)
This uses a class:
public class User
{
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I would like to extend the functionality of this without breaking the existing endpoint for current clients.
All clients make requests to the RESTful endpoint using an instance of System.Net.Http.HttpClient. They accept the JSON response and deserialize it into a list of User instances:
var user = JsonConvert.DeserializeObject<User>(content);
I would like to add a property to the User class:
public IList<string> Countries { get; set; }
I do not want this to break the endpoint for existing clients. That is, I want them to be able to continue deserializing into instances of their User class without problems.
I would also like them to be able to deserialize into an updated version of the User class if they wish to take advantage of the updated functionality.
The extended functionality would be implemented in the endpoint. It would detect if the Countries list has been provided in the request and, if so, perform a different operation and, thus, return a response - one which includes the Countries list.
Is this possible to do without breaking the endpoint for existing clients?
In my experience, adding data like this is generally not a problem.
If you send the data to the client, there is no need for them to expect or use it.
They may not have a property to deserialise countries into, but that shouldn't be a problem.
They don't see it, don't use it, etc.
The signature of your method is not changing (you are still basically expecting a User object) so everyone could still use the same endpoint. If they happen to supply countries, then they will be deserialised into your newer model. If they don't supply countries, then that property will not be set.
It is then up to you to decide what to do based on whether that data is provided.
As you might expect, this is a rough answer based on my own experience.
Your situation may be (is likely) to be more complicated than expressed by the question, but hopefully this provide some help.
Related
I have created a class to store data from API calls I am making. It returns JSON with some meta information, and then an array of data depending on the call being made. The meta information will always have the same fields, so I have created a "Root" class for this, but the data will be different depending on the call being made, so I have created different classes for each type of data, e.g. user data, company data, etc. As shown below, I currently have the "data" property set to a list of objects, but I am trying to figure out the best way to incorporate the different types of data that can be returned, since it will vary based on the call being made.
Right now I have the data saved as a list of objects, but I would like this to change depending on what data I am receiving. Like, if I am retrieving users, I would like for it to be a list of users.
What is the ideal way to accommodate for this? The only way I can think to do it now is to create a different "Root" class for every type of data I am expecting to receive, but that doesn't feel like it should be the most concise way to do it. I was looking into making this a factory design pattern but I wasn't sure that it fit this scenario.
Just use a generic base class:
public abstract class ApiCallResult<T>
{
// With your properties
// public int Limit { get; set; }
// [...]
//
public IEnumerable<T> Data { get; set; }
}
Then define a result per api call.
public class UserApiCallResult : ApiCallResult<User>
{
}
Created a small working example here:
dotnet fiddle
I have to build a .NET Core REST API and I have about two dozen endpoints that take in simple JSON objects like:-
{
"foo": 23,
"bar": "bar_value"
}
and
{
"foo": 12,
"baz": true
}
etc.
Some properties, such as foo above, are common among several endpoints but have different validation requirements. In some endpoints they are required, in others, they are not and so on. I can't change these JSON payloads as they're generated by a third party I don't have any control over.
How can I map these parameters to endpoints in a .NET Core API method directly, without a class?
I can, of course, create a class for each endpoint, such as
public class SomeObject
{
[Required]
[Range(0, 100)]
public int? Foo { get; set; }
public string bar { get; set; }
}
public class SomeOtherObject
{
public int? Foo { get; set; }
[Required]
public bool Baz { get; set; }
}
...
Note the different validation rules.
But I don't feel like creating some two dozen classes. I'd much rather just specify them directly in the endpoint method:
[HttpPut]
[Route("/some-route")]
public IActionResult SomeAction([Required, Range(0, 100)] int? foo, byte? bar)
{
...
}
[HttpPut]
[Route("/some-other-route")]
public IActionResult SomeOtherAction(int? foo, [Required] baz)
{
...
}
It would be much easier to read and figure out which property is required and when by just looking at the methods instead of opening one of two dozen similarly named class files or opening one single file with two dozen similarly named classes with properties of the same name.
So how can I get .NET Core to parse the JSON and assign the property values to the action method parameters?
I'm not aware of a direct answer to this question as specified, so I'll answer this with an alternative approach as an XY problem based on your statement "It would be much easier to read and figure out which property is required and when by just looking at the methods".
This assumes there's not an easy way document your own API surface area if you're using classes. In your example, you're already writing a large amount of logic in the method signature itself, not to mention potential behaviors for default values, etc., that can make those signatures progressively harder to read and understand, and that's exactly what input model classes and model validation are designed to help encapsulate. Furthermore, now that you've decomposed the model into its parts, it becomes increasingly complex to handle validation issues as a cohesive model, regardless of whether it could be done. By accepting the entire object at once, you can run a ModelState.IsValid check, aggregate errors, or add your own and quickly return that from the controller.
By adding XML documentation to your endpoint methods and input model classes, you also open up the easy path of adding a Swagger page with Swashbuckle, which will provide a simple way for you to inspect what the model value types are and which ones are required, etc., as well as example JSON bodies in the Swagger page itself with full documentation as to the purpose of all the parameters.
While you do end up with a bunch of model classes, it's just a button press away from Visual Studio to hop to your class and see your validation requirements and input types while "in code". If class generation is frustrating, you can quickly drop your JSON samples into a class generator online and get a "pretty good" starting point for the input models: https://json2csharp.com/
I'm in the middle of refactoring an analytics api which needs to allow clients to send events as HTTP GET requests, with their "Hit" data encoded in the URL's QueryString Parameters.
My API's job is to recieve these events, and then place the "valid" events onto a queue in another part of the system for processing.
Some Hits have the same shape. The only thing that makes them different is the value of the type parameter, which all events must have at a minimum.
The problem I've encountered is that based on the Hit type, I'd like to be able to assume the type of each field given to me, which requires model binding. Of course. Currently, I can only find out what model to validate against after checking the value of type - which risks making the API excessively "stringly typed"
An example route would be:
GET https://my.anonymousanalytics.net/capture?type=startAction&amount=300&so_rep=true
Therefore, my Hit would be:
{
type: "startAction",
amount: 300,
so_rep: true
}
Which, hypothetically, could be bound to the Model StackOverflowStartHitModel
class StackOverflowStartHitModel {
public string type { get; } // Q: Could I force the value of this to be "startAction"?
? public int amount { get; }
public boolean so_rep { get; }
}
Why am I asking this here? Well I'm normally a JavaScript developer, but everyone who I'd normally turn to for C# wisdom is off work with the flu.
I have experimented with the [FromQuery] attribute decorator, but my concern is that for Hits that are the exact same shape, I might not be able to tell the difference between whether it is a startAction or an endAction, for example.
you're going to need to have a validation engine of some sort, but do not confuse this with your UI model validation. It sounds like you really have one model with a number of valid states which really is business logic.
Your model looks like this:
public class StackOverflowModel
{
public string type { get; set;}
public int amount { get; set; }
public bool so_rep { get; set;}
}
it doesn't matter what value your type field has and you don't need to hard-code it either, it will be captured as is and then it can be checked against valid states.
There are a number of ways to do this, that I can think of.
One option would be to create a list of valid rules ( states ) and then simply check if your input model matches any of them. One way to implement something like this could be with a library like FluentValidation. You can see an example here: Validation Rules and Business Rules in MVC
Another option would be to use some sort of Pattern Matching techniques like described here: https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching
Whichever option you go with, make sure you put this validation stuff in a separate class, maybe even a separate project. You can then add tests for each rule that you have to make sure everything works. This will also keep your controller light.
You haven't given examples of valid and invalid states, but I am guessing you're really talking about variations of those 3 parameters such as, when type is "something" then amount can only be < 200 and so_rep can only be "whatever". This can be done quite nicely with the FluentValidation library.
I have reviewed Microsoft's tutorials on RESTFUL APIs and though I have a general understanding of how to create one, I'm at a lost on what exactly I should do.
Scenario: I have a separate Windows program that contains an API you can use written in C#. The program's job is to take a series of locations and return the mileage for those locations. A DLL is used for this. I want to create a separate program (a RESTFUL web service in C#) that users can enter the values through a URL to obtain the mileage. The user can enter 2 or 20 locations maximum. There are also different types of mileages (modules) that can be used to return different types of mileages (the separate windows program handles this).
A location would have the following properties: ID, City, County, State, Zip Code.
I'm not exactly sure how to implement this. What should be in my class? What should be in my controller exactly? I was thinking I could have a single class that keeps track of all the properties of a location.
My biggest concern is also the controller. I'm not sure how to write it because I don't know how the URI should be. I think that a uri like /mileagetype/loc1/loc2/loc3/locx... might be too lengthy since the user can enter up to 20 locations.
You can create WCF Rest WebService to separate out the functionality from your app. Have a look at this article for creating rest full webservices
You can easily use Web Api 2.0 for this. Which is what it was intended for and is perfect for your use case.
Getting started with Web Api 2.0 from Microsoft
Your web API controller would contain just the end point, via URI's to the outside world and you would then go to your DLL for all of the actual logic.
For example on the client side they can pass you an entire complex JSON object that contains all of the properties you mentioned. On the server side (inside your Web API project) you can have a data transfer object with it's sole purpose is to bind to that JSON data coming from the client.
A simple solution:
On the Server your controller to handle the end-points can look like the below example for a very simple GET request.
public class MileageServiceController : ApiController
{
// GET: api/MileageService?locations=100NewYork&locations=300NewJersey
public string Get([FromUri] String[] locations)
{
String value = String.Empty;
//TO DO - GOT TO DLL and get milage
foreach (String loca in locations)
{
//you could go to your DLL here
//value += DLL.GetMilage(loca.ID, loca.City, etc...
value += loca; //for testing
}
return value;
}
}
I wouldn't worry too much about how long the URL will get that isnt really a problem since
it will more than likely be generated by a client consumer which will be implemented in JavaScript or any other programming language.
A more elegant solution:
For the more elegant solution you can create a DTO (Data Transfer Object) on your server side API.
From there you can then pass complex objects from the client via a POST.
Your DTO can look like this:
public class Location
{
public int ID {get; set;}
public string City {get; set;}
public string County {get; set;}
public string State {get; set;}
public int ZipCode { get; set; }
}
Your Controller can look like this:
// POST: api/MileageService - accept an array of location DTO's
public void Post([FromBody]Location[] locations)
{
//Go to DLL and figure out milage for each DTO
}
More on complex types and web API
This may be a philosophical question, but I thought I'd ask it here since I'm suffering from a bit of analysis paralysis.
I'm currently working on a browser based game (Client-side HTML/Javascript, and WCF Web Services to reach the backend) and I'm trying very hard to have a nice, rich Domain Model.
So here's my question. I have a class called Squadron
public class Squadron
{
public string SquadName { get; set; }
public User Owner { get; set; }
public int XPosition { get; set; }
public int YPosition { get; set; }
public int XTarget { get; set; }
public int YTarget { get; set; }
}
The Squadron is owned by a User
public class User
{
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public int UserID { get; set; }
public List<string> Roles { get; set; }
}
I also have a Squadron repository that returns a fully populated Squadron object, based on it's ID. I have a webservice (basically, GetSquadron) that should return the Squadron. However, the attached User object has some information that I probably don't want exposed to any client (Password, as an obvious example). Although it seems that Password should be a part of this Domain object...it doesn't seem like something I always want populated.
I've considered adding another layer of logic (after the Domain object has been populated) that will ensure that the calling user has access to certain fields, but I was wondering what best practices I can find in the community. I tried Googling but I haven't had much luck.
Thanks!
EDIT: Before anyone harps on it, the password is hashed. I never store a clear-text password in the database. I just figured that I probably shouldn't be returning the password, encrypted or not.
EDIT 2 (Phillip): I've populated the User object because I do need a couple of those fields down in the client side (Username and UserID, and possibly Email). Maybe creating some DTO's is the answer to the problem. I guess I thought it'd be nice to have a common model across all layers.
I would consider substituting the Owner (User) property for the UserID property. I don't see any real reason that you would need the entire User object in Squadron. However, I don't know your design or intent well. It is also a very bad practice to pass around a user password even if it's encrypted.
If you do need the Person details in the Squadron object I'd suggest creating a new Person view model that does not include the user Password.
I agree with PhillipPDX about not passing around the password, but I would be hesitant to use DTOs to pass data from a web service.
If I'm understanding that tech right, you would create the DTO, serialize the object which is then returned by the web service. Typical object serialization tends to carry a lot of overhead and results in larger amounts of data being returned from the service, and an object that requires .Net on the client side to deseralize the data back into an object (DTO).
A more modern approach would be to use something like NewtonSoft's JSON Serializer to convert the POCO (Plain Ol' C# Object) into a JSON string which is then returned by the web service. Since your game is browser / Javascript based JSON would be a natural fit for this use case.