Controllers and routing

A DelphiMVCFramework application has always the fllowing architecture:

  • One Application
  • Many Controllers
    • A Controller is a class inherited from TMVCController
  • Many actions for each controller
    • Controller actions are its methods instrumented with specific RTTI attributes

Then each controller is addressed using a piece of URL and each action is selected using the second part of the URL.

Example: www.myserver.com/blog/posts/2016

  • Server name: www.myserver.com
  • Controller: blog (will be mapped to a controller to instantiate)
  • Action: posts (will be mapped to a method to call)
  • Action' URL parameter: 2016 (parameter to pass to the action, it is optional and defined by the action itself)

Understanding routing is fundamental part of any DMVCFramework development. If you dont know how the router works, you cannot write proper RESTful service.

The router is based upon 4 RTTI attributes. The most important one, and the only always required is MVCPath.

MVCPath attribute

The MVCPath attribute is the most important because it defines the first routing to which the controller should respond. It is also the only attribute required. The MVCPath attribute is applicable to the controller and to the action itself. Its syntax is quite simple: MVCPath('/path'). Let's see the following example.

type
  [MVCPath(‘/blog’)]  //at controller level
  TBlog = class(TMVCController)
  public
    [MVCPath(‘/posts/($year)/($month)/($title)’)]  //at action level
    procedure GetArticle(CTX: TWebContext);
  end;

The controller defines the resource name blog while the action defines the nested resource posts.

Please, note the URL parameters defined in the MVCPath attribute at the action level.

The syntax to define URL parameter is: ($paramname)

Here are some URI which matches with the previous controller/action:

  • /blog/posts/2011/05/a-brand-new-framework
  • /blog/posts/2013/05/rest-rest-for-delphi
  • /blog/posts/1/5/thisAndThat
  • /blog/posts/2013/05/123

The following URI don't matches with the previous controller/action:

  • /blog/posts/2011 (lacks some required parameters, dmvcframwork will return 404: Not Found)
  • /posts/2013/05/rest-rest-for-delphi (there isn't a controller named posts, dmvcframwork will return 404: Not Found)

If we'd like to define a resource which returns the posts by year, we could add another nested resource as follows:

type
  [MVCPath(‘/blog’)]  //at controller level
  TBlog = class(TMVCController)
  public
    [MVCPath(‘/posts/($year)’)]  //at action level
    procedure GetPostsByYear(CTX: TWebContext);

    [MVCPath(‘/posts/($year)/($month)/($title)’)]  //at action level
    procedure GetArticle(CTX: TWebContext);
  end;

Now, the service will response also to URI like the following:

  • /blog/posts/2011/05/a-brand-new-framework (specific article)
  • /blog/posts/2013 (all the posts written in the 2013)
  • /blog/posts/2016 (all the posts written in the 2016)

Please, note that action parameter of by TWebContext is optional. In case you dont use it you can access to the same object defined at controller level named Context. Considering this, the previous actions can be rewritten as follows:

type
  [MVCPath(‘/blog’)]  //at controller level
  TBlog = class(TMVCController)
  public
    [MVCPath(‘/posts/($year)’)]  //at action level
    procedure GetPostsByYear;

    [MVCPath(‘/posts/($year)/($month)/($title)’)]  //at action level
    procedure GetArticle;
  end;

And the parameters can be accessed as following into the actions:

procedure TBlog.GetPostsByYear;
var
  lYear: String;
begin
  //Context is a controller property
  lYear := Context.Request.Params['year'];
  //do something with year
end;

procedure TBlog.GetArticle;
var
  lYear, lMonth, lTitle: String;
begin
  //Context is a controller property
  lYear := Context.Request.Params['year'];
  lMonth := Context.Request.Params['month'];
  lTitle := Context.Request.Params['title'];
  //do something with the variables
end;

Strongly Typed Action

DelphiMVCFramework router can automatically inject values into actions reading them from the MVCPath attribute. Using strongly typed actions, the sample controller become as follows:

type
  [MVCPath(‘/blog’)]  //at controller level
  TBlog = class(TMVCController)
  public
    [MVCPath(‘/posts/($year)’)]     
    //the parameter must have the same name as defined in the MVCPath
    procedure GetPostsByYear(year: String); 

    [MVCPath(‘/posts/($year)/($month)/($title)’)]
    procedure GetArticle(year: String; month: Integer; title: String);
  end;

And the parameters are accessed as following into the actions:

procedure TBlog.GetPostsByYear(year: String);
begin
  //do something with year
end;

procedure TBlog.GetArticle(year: String; month: Integer; title: String);
begin
  //do something with the parameters
end;

Strongly typed actions supports the following data types:

  • Integer (es. /controller/myaction/1234)
  • Int64 (es. /controller/myaction/1234)
  • Single (es. /controller/myaction/1234.52)
  • Double (es. /controller/myaction/1234.5467)
  • Extended (es. /controller/myaction/1234.5467)
  • Boolean (es. /controller/myaction/true or /controller/myaction/true)
  • TDate (es. /controller/myaction/2016-12-20)
  • TTime (es. /controller/myaction/14:12:59)
  • TDateTime (es. /controller/myaction/2016-12-20 14:12:59)
  • String (es. /controller/myaction/mystring)

In the unit tests there are all the possibile cases explained.

MVCHTTPMethod attribute

TODO

MVCProduces attribute

TODO

MVCConsumes attribute

TODO

results matching ""

    No results matching ""