servicestack request best approach to implement search - servicestack

What would you guys recommend as being the best way to implement search in servicestack. For instance at the moment I have an advanced search form which in the backend simply builds up a linq query dynamically. If I wanted to expose the search feature using service stack what is the best way to go about it.
I have seen some people using the idea of creating a request property like [object].FirstnameStartsWith , [object].SurnameContains etc

I went with something like this
[Route("/things", "GET")]
public class ThingList
{
public string Term { get; set; }
public int Take { get; set; }
public int Skip { get; set; }
}
public partial class ThingService : Service
{
public object Get(ThingList req)
{
var query = this.Things // from somewhere
if(!string.IsNullOrEmpty(req.Term))
query = query.Where(x => x.Name.Contains(req.Term));
if(req.Skip > 0) query = query.Skip(req.Skip);
if(req.Take > 0) query = query.Take(req.Take);
return query.ToList();
}
}

There's no best way to design APIs for services, but your goals should be to be as descriptive and user-friendly as possible so clients can determine exactly what the service does by just looking at the request DTO.
Generally services should be cohesive and relevant for the use-case of the clients call context consuming them, e.g adding a new field/feature for that request should have the potential to be useful for existing clients already consuming that service.
Searching and Filtering a result-set is good example of this where every field/feature added is filtering the target result-set.
Other concerns I have when designing services is cache-ability, i.e. I separate long-term cacheable results from short-term non-cachable info.

Related

Get request with multiple inputs in ServiceStack API

I am creating a endpoint that accepts multiple parameters. I was wondering what the proper way of doing this in ServiceStack is, as I know that the routes can be defined like this:
[Route("/Cars/{EquipmentIds}/{ManufacturerIds}/{ColourIds}")]
But does not that mean that EquipmentIds has to be defined before ManufacturerIds and ColourIds, otherwise the API will interpret it incorrectly?
I would like to specify the parameters I use, and then not include the rest when they are not used.
A unclean url would then look like this ?EquipmentIds=1&ColourIds=1
I found the following solution, but this one was from 2011
Multiple Optional Parameters with ServiceStack.Net.
Is there a new solution for this, or is that still the proper way of doing things?
The URL should be a "resource identifier" where any Query String arguments are modifiers to that resource request.
So you shouldn't put complex types in the /path/info which are unlikely to form part of Resource Identifier for that route.
Your route should be self-describing as to what it's a resource identifier of. Stuffing a an anonymous bunch of ids in the URL doesn't make it a clean URL, it still needs to be semantically correct and self-describing at what the different path components contain.
It's hard to know the right Route to use when it's not clear what Service this is used for, but if this was a Car Search Service the appropriate URL would be something like:
/cars/search?EquipmentIds=1,2,3&ManufacturerIds=4,5,6&ColourIds=7,8,9
Just as when you use a Search Service like Google, they don't try to pack everything in the route, which is only used to identify you're making a search request. Everything else including the search query is added to the query string, e.g;
https://www.google.com/search?q=test
Which in ServiceStack would just be defined as:
[Route("/cars/search")]
public class SearchCars
{
public List<int> EquipmentIds { get; set; }
public List<int> ManufacturerIds { get; set; }
public List<int> ColourIds { get; set; }
}
Or it can be easily auto implemented in AutoQuery with:
[Route("/cars/search")]
public class SearchCars : QueryDb<Car>
{
public List<int> EquipmentIds { get; set; }
public List<int> ManufacturerIds { get; set; }
public List<int> ColourIds { get; set; }
}

How do I perform model binding on a HTTP POST in Azure Functions?

I want to bind my HTTP POST parameters to Azure functions, and want to ensure the untrusted data is correctly mapped to my model class.
Right now I'm using a mime type of application/json , and I may need to also support FORM Post and Protobuf.
Since I know support for the latter is a bit complex, how can I perform simple model binding for JSON data?
I've spent a lot of time reading about HTTP triggers, skimming all pages of the Azure Function docs, but don't see anything that helps with this issue. I suspect there is a lower level technology I need to research (webjobs?) for this.
If your HttpTrigger function is configured to accept JSON POST requests, you can bind to your custom model type as follows:
using System.Net;
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public static async Task<HttpResponseMessage> Run(Person person, HttpRequestMessage req)
{
return person.FirstName == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Who are you?")
: req.CreateResponse(HttpStatusCode.OK, $"Hello {person.FirstName}!");
}

More ServiceStack request DTO advice

This is a follow up regarding:
ServiceStack Request DTO design
In the above question the design was strictly regarding read operations. What about write operations? Say we wanted to add operations for creating a new booking limit, would reusing the noun be appropriate here?
[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
BookingLimit newBookingLimit
}
-OR- Would this be better design?
[Route("/bookinglimits/","POST")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; } }
}
Also, if we wanted to add editing--should we have insert and edit share the same models and add the ID?
[Route("/bookinglimits/","POST")]
[Route("/bookinglimits/{Id}/","PUT")]
public class CreateBookingLimit : IReturn<BookingLimit>
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; } }
}
I'm trying to wrap my head around when it makes the most sense to reuse POCOs and when it makes more sense to separate intentions.
Message-based API Design
There are a few things to bear in mind when designing the ideal message-based API where your Services effectively end up serving 2 masters: a Native Client API and a REST API. Native Clients just send and receive messages in their original form so they get a natural API for free modelled using C# Request and Response DTOs to capture what information is required for the Service to perform its Operation and what it should return.
Projecting messages into the ideal HTTP API
After designing your message-based API you'll then want to focus on how best to project the messages into a REST API by annotating Request DTOs with [Route] Attributes to define the Custom endpoints for your Services.
This previous answer on Designing a REST-ful service with ServiceStack provides examples on which routes different Request DTOs map to, in general you'll want to design your APIs around Resources where each operation "acts on a Resource" which will make defining your Custom Routes easier. The ideal HTTP API for Creating and Updating a Booking Limit would look like:
POST /bookinglimits (Create Booking Limit)
PUT /bookinglimits/{id} (Update Booking Limit)
General recommendations on good API Design
Whilst not specifically about Web Services this article on Ten Rules for Good API Design provides good recommendations on general (Code or Services) API design. As API Consumers are the intended audience of your APIs who'll primarily be deriving the most value from them, their design should be optimized so that they're self-descriptive, use consistent naming, are intuitive to use and can be evolved without breaking existing clients. Messages are naturally suited to versioning but you still need to be mindful when making changes to existing published APIs that any additional properties are optional with default fallback behavior if required.
For this reason whilst you can save some code by returning a naked BookingLimit, my preference is to instead return a specific Response DTO for each Service which allows the Service to return additional metadata without breaking existing clients whilst maintaining a consistent Request/Response pattern for all Services. Although this is just my preference - returning naked types is also fine.
ServiceStack Implementation
To implement this in ServiceStack I wouldn't use the same Request DTO to support multiple verbs. Since the Request DTO is called Create* that conveys that users should only send this Request DTO to Create Booking limits which is typically done using a POST request, e.g:
[Route("/bookinglimits", "POST")]
public class CreateBookingLimit : IReturn<CreateBookingLimitResponse>, IPost
{
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class CreateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
The IPut, IPost are Verb interface markers which lets both the User and Service Client know which Verb this message should be sent with which makes it possible to have all messages sent in a single Service Gateway method.
If your Service also supports updating a Booking Limit then I'd create a separate Service for it which would look like:
[Route("/bookinglimits/{Id}", "PUT")]
public class UpdateBookingLimit : IReturn<UpdateBookingLimitResponse>, IPut
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class UpdateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
By using separate Operations you can ensure Request DTOs contains only the properties relevant to that operation, reducing the confusion for API consumers.
If it makes sense for your Service, e.g. the schemas for both operations remains the same I'll merge both Create/Update operations into a single Operation. When you do this you should use a consistent Verb that indicates when an operation does both, e.g. Store* or CreateOrUpdate*:
[Route("/bookinglimits", "POST")]
public class StoreBookingLimit : IReturn<StoreBookingLimitResponse>, IPost
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class StoreBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
In most cases where the Server generates the Id for the Resource you should use POST, in the rare case where the client specifies the Id, e.g. Slug or Guid you can use PUT which roughly translates to "PUT this resource at this location" which is possible when the client knows the url for the resource.
Message based API examples
Most of the time what messages should contain will be obvious based on the Service requirements and becomes intuitive and natural to create over time. For examples on a comprehensive message-based API you can have a look AWS Web Services who've effectively servicified their Web Services behind a message-based design that uses Service Clients to send messages to access all their APIs, e.g. AWS DynamoDB API Reference lists each Actions that's available as well as other DTO Types that the Services return, e.g here are DynamoDB APIs they have around Creating / Modifying and Querying Items:
Actions
BatchGetItem
BatchWriteItem
DeleteItem
GetItem
PutItem
Query
Scan
UpdateItem
Data Types
AttributeDefinition
AttributeValue
AttributeValueUpdate
Condition
...
In ServiceStack Actions are called Operations and what you'll use Request DTOs to define, whilst AWS Data Types are just called DTOs which I keep in a Types namespace to differentiate from Operations.
DynamoDb.ServiceModel (project)
/GetItem
/PutItem
/UpdateItem
/DeleteItem
/Query
/Scan
/Types
/AttributeDefinition
/AttributeValue
/AttributeValueUpdate
You typically wouldn't need additional explicit Services for Batch Requests as you can get that for free using ServiceStack's Auto Batched Requests. ServiceStack also includes a number of other benefits where it's able to generate richer DTOs containing Custom Attributes and interfaces in the Source DTOs to enable a richer and succinct end-to-end typed API requiring less boilerplate and generated code that lets you use the same Generic Service Client to call any ServiceStack Service offering both Sync and idiomatic Async APIs. The additional metadata also enables seamless higher-level functionality like Encrypted Messaging, Cache Aware Clients, Multiple Formats, Service Gateway, HTTP Verb Interface Markers, etc.
Otherwise AWS follows a very similar approach to ServiceStack for designing message-based APIs using generic Service Clients to send DTOs native in each language.

C# MVC Entity Framework with testability

I'm thinking a bit about "best practice" regarding testability and the best way to define a particular action.
In the SportsStore application (from Pro ASP.NET MVC 4), for the AdminController, we have the following two methods in the AdminController.cs file:
IProductRepository
namespace SportsStore.Domain.Abstract {
public interface IProductRepository {
IQueryable<Product> Products { get; }
void SaveProduct(Product product); //Defined in EFProductRepository
void DeleteProduct(Product product); //Defined in EFProductRepository
}
}
AdminController:
private IProductRepository repository;
public ViewResult Edit(int productId) {
Product product = repository.Products.FirstOrDefault(p => p.ProductID == productId);
...
}
[HttpPost]
public ActionResult Delete(int productId) {
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
...
}
As I noticed, we are basically doing the same bit of logic, that being, finding the productID. If productId changes at all, to something else, we need to change this in two spots. This can be tested, easily, though, since the controller itself is making the Linq call.
I was thinking that I could put this into the equivalent of the EFProducts (so the database implementation of the IProducts interface), but this creates a tie to a database state of some kind. I'd like to avoid this in my unit tests as it increases testing complexity a fair amount.
Is there a better place to put this FindOrDefault logic, rather than in the controller, yet keep a good amount of testability?
Edit1: Adding the definition for the repository, which points to an interface
The responses under my question discuss the possibilities. Both the book and #maess agree in keeping the logic for this particular part in the controller. The comments under my question are worth looking at, as both #SOfanatic and #Maess provided fantastic input.

Request DTO map to Domain Model

I have the following Domain Model:
public class DaybookEnquiry : Entity
{
public DateTime EnquiryDate { get; set; }
[ForeignKey("EnquiryType")]
public int DaybookEnquiryTypeId { get; set; }
public string AccountNumber { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
#region Navigation Properties
public virtual User User { get; set; }
public virtual DaybookEnquiryType EnquiryType { get; set; }
public virtual ICollection<DaybookQuoteLine> QuoteLines { get; set; }
#endregion
}
This is inside of a project named DomainModel. Entity is just a base class which my domain models inherit from, it contains an Id field.
I then have other projects inside my solution called ServiceInterface and ServiceModel. ServiceInterface contains all my services for my application and ServiceModel contains my DTO's and routes etc.. I'm trying to follow the guidelines set out here: Physical Project Structure
My EnquiriesService contains a method to create a new enquiry in my database using a repository:
public void Post(CreateEnquiry request)
{
// Not sure what to do here..
// _repository.Insert(request);
}
My CreateEnquiry request looks like so:
[Api("POST a single Enquiry for Daybook.")]
[Route("/enquiries", "POST")]
public class CreateEnquiry : IReturnVoid { }
As you can see, the CreateEnquiry request object is empty. Do I need to add properties to it to match my Domain Model and then use AutoMapper or something similar to map the fields to my Domain Model and pass that into my repository?
The Insert method on my repository looks like so:
public virtual void Insert(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
DbContext.SaveChanges();
}
Yes. Your Service request, in this case CreateEnquiry needs to have all the properties you need in order to do whatever it is you want to do!
I've seen two different models for Create vs Update:
Use one request objects called, say, SetEnquiry that has a nullable id field. When null and using the POST HTTP verb, it internally creates a new object. And when not null and using the PATCH HTTP verb, it internally updates an object. You can use ServiceStack's implementation of AbstractValidator<T> to add logic such as if POST then id field needs to be null; and if PATCH then id field cannot be null. This will help ensure your data is always as it needs to be.
Create two request objects -- one for Create and one for Update. The Create doesn't even have an id field, and the Update has one and requires it. You can use the same validation technique used above, except applied to each class independently, so you don't need the conditional check of if this verb do this; if that verb do that.
How you map to your data model is up to you. You can use something like AutoMapper or you can use ServiceStack's built-in TranslateTo and PopulateWith methods. I personally take a middle ground: I created my own object extension methods called MapTo and MapFrom that interally call TranslateTo and PopulateWith respectively. Why did I do this? Because then I control those extensions inside my own namespaces and when I need to do special mappings (like a column name doesn't match up, or one object is more complex than the other, or I simply want to ignore a particular column from one of the objects) I simply overload the MapTo and MapFrom with explicit types, giving it higher specificity than the generic methods.
So back to your question specifically. Assuming you're using the built in TranslateTo your service method might look like this:
public void Post(CreateEnquiry request)
{
_repository.Insert(request.TranslateTo<Enquiry>());
}
One more thing: I generally return the object itself when doing a Create and Update. As fields can change (auto-calculated fields, for example) I like to return the object back to the caller. This is preference and has no real bearing on the answer I'm giving you. Just throwing it out there!

Resources