The attributes
One of WiRL's distinctive features is its ability to let developers write ordinary classes using standard native objects and types, and then "remotize" the methods of these classes. To understand how these methods should be used in the context of a REST call, WiRL relies on a series of Attributes that must be applied to the class, its methods, and parameters. These attributes are found in the WiRL.Core.Attributes unit, and we'll analyze them in detail in the following sections.
WARNING
If you forget to add the unit with the definition of the attributes Delphi will generate a Warning: W1074 Unknown custom attribute
. The program will still compile but will not work. From Delph 10.3 you can transform the Warning into an error in the Delphi options or for a single project.
Attribute: Path
This attribute must be applied to a class, in that way WiRL will consider it a resource. It can applied to a method too, then the two paths will be combined together in a new sub-resource.
[Path('user')]
TUserResource = class(TObject)
public
[GET]
[Produces(TMediaType.APPLICATION_JSON)]
function GetUser(...): ...;
[GET]
[Path('{id}/todo')]
[Produces(TMediaType.APPLICATION_JSON)]
function GetUserTodo(...): ...;
In this example the /user
path will be accessible via the path GetUser method. In the second example the path contains a template Path('{id}/todo')
. Templates are strings that contain variable parts (in this case id) that are accessible to the method via the attribute PathParam
explained below. This method will then be accessible from URLs like /user/12/todo
or /user/lminuti/todo
.
However, the full URL of the resource will also depend on the configuration set to TWiRLServer
, TWiRLEngine
and TWiRLApplication
as explained here.
Attribute: GET
Applied to a class method. The method should be called only if the HTTP method is GET
.
Attribute: PUT
Applied to a class method. The method should be called only if the HTTP method is PUT
.
Attribute: POST
Applied to a class method. The method should be called only if the HTTP method is POST
.
Attribute: DELETE
Applied to a class method. The method should be called only if the HTTP method is DELETE
.
Attribute: Produces
As we saw previously, WiRL associates the resource with the method of a class based on the attributes indicating the HTTP method and the path. However, the client can also indicate, via the Accept header, the desired response format. The Produces
attribute must indicate one or more formats in which the method is capable of returning the response.
Warning : This attribute is used only to "match" between request and method. That WiRL will execute the method code which will presumably return something as output. It's only at the end of this process that WiRL, through the message body writers, will attempt to convert the output into the required format. In the absence of an appropriate message body writer WiRL will return the error
415 - MediaType [%s] not supported on resource [%s]
.
Attribute: Consumes
This attribute behaves similarly to Produces
but with respect to a resource's input. With the PUT and POST methods, for example, a message is sent to the server. The format of the message is indicated by the Content-Type header. In this case the header must match what is declared with the Consumes
attribute. Once this has been done via the attribute BodyParam
it will be possible to read the message sent by the client.
[Path('user')]
TUserResource = class(TObject)
public
[POST]
[Consumes(TMediaType.APPLICATION_JSON)]
[Produces(TMediaType.APPLICATION_JSON)]
function AppendUser([BodyParam] AUser: TUser): TUser;
end;
In this example the method AppendUser
expects a message in JSON format. If the message is indeed in this format WiRL will look for a message body reader capable of transforming a JSON into TUser. If it doesn't find it it will return the error Unsupported media type [%s] for param [%s]
.
Attribute: PathParam
If a URL has been defined via the attribute Path
containing a template, the content of the template will be associated with the parameter decorated with the attribute PathParam
.
[Path('user')]
TUserResource = class(TObject)
public
[GET]
[Produces(TMediaType.APPLICATION_JSON)]
function GetAllUsers(): TObjectList<TUser>;
[GET]
[Path('{id}')]
[Produces(TMediaType.APPLICATION_JSON)]
function GetUserById([PathParam('id')] AId: Integer): TUser;
[GET]
[Path('{id}/todo/{category}')]
[Produces(TMediaType.APPLICATION_JSON)]
function GetUserTodo(
[PathParam('id')] AId: Integer
[PathParam('category')] const ACategory: string
): TObjectList<TTodo>;
Let's consider several URLs:
/user
: This path will cause the method to be calledGetAllUsers
/user/12
: In this case the method will be calledGetUserById
and the value 12, which is part of the template, will be passed to the parameterAId
. In fact, the name of the template parameterId
matches the value of the attributePathParam
./user/12/todo/done
: in this case theGetUserTodo
method will be called and the parametersAId
andACategory
receive 12 and the done string.
Attribute: QueryParam
QueryParam allows you to capture parameters passed via query string.
[Path('user')]
TUserResource = class(TObject)
public
[GET]
[Produces(TMediaType.APPLICATION_JSON)]
function GetUser(
[QueryParam('name')] const AName: string;
[QueryParam('email')] const AEmail: string
): TObjectList<TUser>;
In this example with a URL like: /user?name=lminuti&[email protected]
WiRL will set the parameters AName
and AEmail
with the appropriate values.
Attribute: FormParam
This attribute works similarly to QueryParam
but searches for parameters in the message body. WiRL, in this case, expects the body of the message to be in the application/x-www-form-urlencoded
format, then decodes it and passes the values to the method parameters.
Attribute: BodyParam
This attribute allows you to read the entire body of the message as long as the format used is compatible with that indicated in the Consumes
attribute and there is someone message body reader capable of transforming the message into the indicated object.
[Path('user')]
TUserResource = class(TObject)
public
[POST]
[Consumes(TMediaType.APPLICATION_JSON)]
[Produces(TMediaType.APPLICATION_JSON)]
function AppendUser([BodyParam] AUser: TUser): TUser;
end;
In this example the AppendUser
method expects a message in JSON format. If this is true WiRL will look for a message body reader capable of transforming a JSON into TUser.
Attribute: HeaderParam
Similar to FormParam
or QueryParam
but looks for the data in a header that must be specified in the attribute.
Attribute: CookieParam
Similar to the previous one but looks for the data in a cookie.
Attribute: MultiPart
This attribute allows reading parameters passed through a multipart/form-data
POST request. In this case, the individual values sent can be read directly or via the TWiRLFormDataPart
class. Let's look at an example:
[POST]
[Path('/multipart')]
[Consumes(TMediaType.MULTIPART_FORM_DATA)]
[Produces(TMediaType.APPLICATION_JSON)]
function PostMultiPartExample(
[FormParam] AValue: string;
[FormParam] AContent: TWiRLFormDataPart;
[FormParam] AJSON: TJSONObject
): TJSONObject;
end;
In this case, the resource expects to find three parameters: AValue
, AContent
, and AJSON
. The first and last are read directly, while the second uses TWiRLFormDataPart
. The advantage of this class is that it allows you to obtain additional information about the parameter. In fact, each part of a multipart message contains special attributes (name, format, compression type, etc.).
Attribute: DefaultValue
This attribute allows assigning a value to a parameter in case it is not provided by the client.
Attribute: Context
The Context attribute is used to obtain special context information as explained here: Context Injection. It can be applied to either a class variable or a method parameter.
Attribute: PermitAll
This attribute (on a method) indicates that the method can be used by anyone as long as they are authenticated.
Attribute: DenyAll
DenyAll blocks a method for any user.
Attribute: RolesAllowed
This attribute (on a method) allows you to specify one or more roles that will have permission to use the method.
Attribute: Singleton
The Singleton attribute applies to either a method or the definition of a class. It indicates whether all instances of the class, or only the one returned by the method it is applied to, should be destroyed at the end of the HTTP call. For more information, see the chapter Memory management.
Attribute: PreMatching
Used to indicate that a filter should be invoked even if the resource, application, or engine does not exist (see Filters).
Attribute: PreMatchingResource
Used to indicate that a filter should be invoked even if the resource does not exist (see Filters).
Attribute: NameBinding
Applied to a custom attribute to create a "bind" between filters and resources (see Filters).
Attribute: Priority
Indicates the priority of a filter (see Filters).