Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
ServiceStack 4 Cookbook

You're reading from   ServiceStack 4 Cookbook Over 70 recipes to create web services, build message-based apps, and work with object-relational mapping

Arrow left icon
Product type Paperback
Published in Jan 2015
Publisher
ISBN-13 9781783986569
Length 444 pages
Edition 1st Edition
Arrow right icon
Toc

Table of Contents (13) Chapters Close

Preface 1. Configuration and Routing FREE CHAPTER 2. Services and Data Transfer Objects 3. Testing and Logging 4. Object Relational Mapping (OrmLite) 5. HTML and Form Data 6. Filters and Validators 7. Security and Authentication 8. Working with Redis 9. Integrating with Other Technologies A. Getting Started B. Testing Locally Index

Routing using data transfer object attributes

ServiceStack routes incoming HTTP requests to services by a number of mechanisms. Perhaps the most convenient is the Route attribute— simply annotate the class to indicate where ServiceStack should expect requests.

Getting ready

You'll need a request object. For instance, Reidson-Industries is interested in developing a group messaging application for use on the Web and on mobile devices. We could model an incoming request like this:

public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

We might handle requests for this Message object with a MessengerService class, as follows:

public class MessengerService : Service
{
  static List<Message> _messages = new List<Message>();
  public MessageResponse Post(Message request)
  {
    _messages.Add(request);
    return new MessageResponse { Response = "OK" };
  }
}

In previous examples, our service methods have simply returned the object, with the service passing a string back. To add a bit more structure to our contract, a response might be modeled like this:

public class MessageResponse
{
  public string Response { get; set; }
}

How to do It...

To tell ServiceStack where to expect requests that contain Message objects, simply annotate the object with a Route annotation, as follows:

[Route("/message")]
public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

How it works...

Now ServiceStack will accept POST requests containing either JSON data or form data at http://yourserver/message containing strings named Body, Sender, and GroupName. These requests will be deserialized in to an instance of the Message DTO. You can provide more information in the annotation as well— for instance, if you wanted to be able to provide an alternate URL format, you could do the following:

[Route("/message")]
[Route("/message/{GroupName}")]
public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

Now, if ServiceStack sees a request for http://yourserver/message/BestFriends, it will assume that Message is destined for the BestFriends group. You can add multiple routes for the same request object by placing multiple Route annotations on the same object.

We'll need to retrieve messages too. We can do that by querying the /group endpoint. To do this, simply create a request object, as follows:

[Route("/group/{GroupName}")]
public class Group
{
  public string GroupName { get; set; }
}

We'll expand MessengerService to be able to handle this request:

public class MessengerService : Service
{
  static List<Message> _messages = new List<Message>();
  public MessageResponse Post(Message request)
  {
    _messages.Add(request);
    return new MessageResponse { Response = "OK" };
  }

  public GroupResponse Get(Group request)
  {
    return new GroupResponse
    {
      Messages = _messages.Where(message => message.GroupName.Equals(request.GroupName))
      .ToList()
    };
  }
}

The GroupResponse class is a simple DTO to model the expected response. In this example, the GroupResponse class has a single property Messages and simple List<Message> containing the messages that the user has requested:

public class GroupResponse
{
  public List<Message> Messages { get; set; }
}

Note

Note that the code in the previous example will work to get us started building a simple application, but storing all of our incoming messages in static List<Message> with no backing store isn't likely to work out well in practice. We'll refactor this into something more production-ready in a later recipe.

Once you start the app, you can send a form post to the BestFriends group with curl. A command-line HTTP utility, curl makes it easy to craft full-featured HTTP requests. It can specify headers and HTTP methods, send form data, and return any results on the command line.

We want to send an HTTP POST request with enough form data to provide a message to our service, and we'd like to see the response in JSON. We'll use curl with -H to specify the header, -X, to specify the HTTP method, and --data to specify the data to send. Put together, it looks like this:

curl -H "Accept: application/json" -X POST --data  \
    "Body=first post&Sender=Kyle&GroupName=BestFriends" \
    http://myserver/message

Then, you can read the messages that have been sent to the BestFriends group, as follows:

curl -H "Accept: application/json" \     
     http://myserver/group/BestFriends

The result would be the JSON response, as follows:

{"Messages": [{"Body":"first post", "Sender":"Kyle","GroupName":"BestFriends"}]}

There's more...

Let's imagine that we wanted people to be able to search for a specific search term or possibly search for a term within a specified group. We could use the Route annotation to do this easily with one single request type. Implement it like this:

[Route("/message/search")]
[Route("/message/search/{Group}")]
public class Search
{
  public string Group { get; set; }
  public string Query { get; set; }
}

We'll easily expand our MessengerService class to be able to handle this request by adding a new method, as follows:

public GroupResponse Get(Search request)
{
    return new GroupResponse
    {
      Messages = _messages.Where(
        message => message.GroupName.Equals(request.Group)
        && message.Body.Contains(request.Query))
      .ToList()
    };
}

We could make use of this new endpoint with another curl command. First, we'll post a few messages so that we have something to search, as follows:

curl -H "Accept: application/json" -X POST \
     --data "Body=first post&Sender=Kyle"  \
     http://myserver/message/BestFriends
{"Response":"OK"}
curl -H "Accept: application/json" -X POST \
     --data "Body=second post&Sender=Kyle"  \
     http://myserver/message/BestFriends
{"Response":"OK"}

Then, we can easily search by sending a simple GET call:

curl -H "Accept: application/json" \    
    http://myserver/message/search/BestFriends?query=second
{"Messages":
  [
    {"Body":"second post",
     "Sender":"Kyle",
     "GroupName":"BestFriends"}
  ]
}
You have been reading a chapter from
ServiceStack 4 Cookbook
Published in: Jan 2015
Publisher:
ISBN-13: 9781783986569
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image