Interfaces

Project

Pages Restful

NuGet packageOwin.Framework.Pages.Restful
GitHub sourceOwinFramework.Pages.Restful

Home |  Readme

[EndpointParameter] attribute | The OWIN Framework Restful

The [EndpointParameter] Attribute

Attach these attributes to a service endpoint method to define the parameters that can be passed to the endpoint. You can also add C# parameters to your method to define the parameters that can be passed to the endpoint, but this only defines the name and the data type of the parameters.

If you prefer to define C# parameters, you can also decorate those parameters with the [EndpointParameter] attribute to define the way in which parameters can be passed and provide documentation, parsing and validation of the parameters.

Example Usage

[IsComponent("math_form")]
[IsService("math", "/math/", new[] { Method.Post })]
public class MathFormComponent: Component
{
    public MathFormComponent(IComponentDependenciesFactory dependencies)
        : base(dependencies)
    {
    }
    [Endpoint(Analytics = AnalyticsLevel.Full)]
    [Description("Adds two numbers and returns the sum")]
    public void Add(
        IEndpointRequest request,
        [EndpointParameter(
            EndpointParameterType.FormField,
            Description = "The first number to add")]
        double a,
        [EndpointParameter(
            EndpointParameterType.FormField,
            Description = "The second number to add")]
        double b,
        [EndpointParameter(
            EndpointParameterType.FormField,
            ParserType = typeof(AnyValue),
            Description = "The path of the page to return the results on")]
        string r)
    {
        request.OwinContext.Set(
            typeof(ArithmeticResult).FullName,
            new ArithmeticResult { Result = a + " + " + b + " = " + (a + b) });
        request.Rewrite(r);
    }
}

The [EndpointParameter()] attribute has the following properties that you can set:

ParameterName

This is the name of parameter that should be used by the caller when calling this service. If the parameter is passed in the query string then this is the name of the query string parameter. If the parameter is passed as a form input then this is the name of the input etc.

The parameter name is not case sensitive. You should choose names that work for query strings, Http headers, form input controls etc. In particular you should avoid using spaces and punctuation in the parameter names.

ParameterType

This is a [flags] enum that defines all of the ways that the caller can pass this parameter to the service. If you do not set this property then it defaults to query string only. The other options are form input, Http header and path element. You can specify as many of these options as you like to provide multiple ways to call the endpoint.

When the ParameterType property includes path element as an option then the UrlPath property of the endpoint must include the name of the parameter in {} to indicate where the parameter appears in the path.

For example:

[Endpoint(UrlPath="invoice/{invoiceNumber}")]
[EndpointParameter("invoiceNumber", typeof(InvoiceNumberParser), EndpointParameterType.PathSegment)]
public void Add(IEndpointRequest request)
{
}

ParserType

The ParserType property of the [EndpointParameter()] attribute specifies how the input parameter should be parsed and validated. The parser can abort the processing of the request returning a custom validation message back to the caller if the parameter is not valid.

For the value of this property you can simply provide a .Net CLR value type such as string, int etc and the framework will simply try to parse the parameter as this type and apply no futher validation. In this situation the parameter will be required by the caller. This technique will also generate minimal documentation for your service endpoint.

To make the parameter optional you can use a nullable type instead, for example int?, double? etc.

The REST framework package includes a few standard parsers based on value types, for example NonZeroValue<T> that can be used like this:

[Endpoint(UrlPath="invoice/{invoiceNumber}")]
[EndpointParameter("invoiceNumber", typeof(NonZeroValue<int>), EndpointParameterType.PathSegment)]
public void Add(IEndpointRequest request)
{
}

For custom types that are application specific you should write custom parsers that can be reused across all of your services, for example you invoice numbers might have a well known format with check digits. You should write this parsing/validation code once only and apply it to all the relevant endpoint parameters.

The IParameterParser interface is easy to implement, but it becomes very simple if you inherit from OwinFramework.Pages.Restful.Parameters.ParameterParser. Below is an example of a parameter parser that validates that invoice numbers are 12 characters long and start with capital 'I'.

using OwinFramework.Pages.Core.Interfaces.Capability;
using OwinFramework.Pages.Restful.Parameters;
public class InvoiceNumberParser : ParameterParser
{
    private const string _wrongLengthError = "The invoice number must be 12 characters long";
    private const string _invalidError = "The invoice number must start with the letter I";
    public override string Description 
    { 
        get 
        { 
            return "A valid 12-character invoice number beginning with the letter I"; 
        } 
    }
    public override string Examples
    {
        get
        {
            return "I00000000001";
        }
    }
    public InvoiceNumberParser(): base(typeof(string))
    {
    }
    public override IParameterValidationResult Check(string parameter)
    {
        var result = new Result { Type = typeof(string) };
        if (parameter == null || parameter.Length != 12)
        {
            result.ErrorMessage = _wrongLengthError;
            return result;
        }
        if (parameter[0] != 'I')
        {
            result.ErrorMessage = _invalidError;
            return result;
        }
        result.Success = true;
        return result;
    }
}

Parameter parsers can optionally implement IDocumented. When this interface is implemented it will be used to provide more detailed documentation on how to call this service endpoint.

Description

If you provide a description here in Html format that it will be included in the auto-generated endpoint documentation for the servie.

If you do not provide a description then a simple description will be provided based on the available information.