Simone
Simone

Reputation: 149

Web Api 2 with two method with the same HTTP verb an angularjs resources

I have this controller:

public class SeguiAttivazioneController : ApiController
{
    [HttpGet]
    public IHttpActionResult DoWork1()
    {
        ...            
        return Ok();
    }

    [HttpGet]
    public IHttpActionResult DoWork2()
    {
        ...            
        return Ok();
    }

    [HttpGet] //I would like to have a search with GET verb, but I cannot validate my ModelState with dataAnnotation
    public IHttpActionResult AnotherSearch(string filter1, string filter2, ...)
    {
        if (ModelState.IsValid)
        {
            ...
            return Ok();
        }
        return BadRequest(ModelState);
    }

    [HttpPost]
    public IHttpActionResult DoSearch(SearchFilter filters)
    {
        if (ModelState.IsValid)
        {
            ...
            return Ok();
        }
        return BadRequest(ModelState);
    }

    [HttpPost]
    public IHttpActionResult SubmitForm(FormData data)
    {
        ...
        return Ok();
    }
}

As you can see I have two methods with same HttpVerbs (2 for GET and 2 for POST)... I don't know if I am violating REST principles... If so, I would like to avoid... In this moment I am using AngularJs + NgResources to call my Controller..

public_area
    .factory("SeguiAttivazioneService", function ($resource) {
        //return {
        //    seguiAttivazione: $resource("/api/SeguiAttivazione/", null,
        //                        {
        //                            'get2': { method: 'GET', url: '/api/SeguiAttivazione/GetActivationStatus2' }
        //                        })
        //};
        return {
            seguiAttivazione: $resource("/api/SeguiAttivazione/")
        };
    });

I am trying to do a GET:

$scope.getActivationStatus = function (event) {
    event.preventDefault();

    if ($scope.segui_attivazione_form.$valid) {
        var request =
            new SeguiAttivazioneService
                .seguiAttivazione()
                .$get({ }, getActivationStatusSuccess, getActivationStatusError);
    }
};

But (correctly) I obtain an "Internal Server Error 500", because I have to GET method. How Can I solve this problem? (I suppose I will have same problem with POST too)

Thank you

UPDATE Here the class of the filters

public class SearchFilter 
{
    [Required(ErrorMessage="")]
    public string CodiceFiscale { get; set; }
    [Required(ErrorMessage = "")]
    [RegularExpression(@"^(?:\d{11,16})|(?:[a-zA-Z]{6}[a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{3}[a-zA-Z])$", ErrorMessage = "Codice Fiscale o Partita IVA non validi")]
    public string CodiceRichiesta { get; set; }
}

With this class I can use data Annotation to validate my model... If I do a GET Method I cannot use data annotation validation anymore...

Upvotes: 1

Views: 800

Answers (2)

Okazari
Okazari

Reputation: 4597

Here is some explanation about a the REST Endpoints.

In REST we are manipulating ressources. As collections or individual.

Classics endpoint would be :

GET /rest/houses DATA : none -> will return a collection of houses

GET /rest/houses/{id} DATA : none -> will return the house find by its {id}

POST /rest/houses DATA : {"street":"3 bdv NY-city"} -> will create a new house object with the given data

PUT /rest/houses/{id} DATA : { "id":"{id}", "street":"4 bvd NY-city"} -> will update the whole house ressource find by its {id}

PATCH /rest/houses/{id} DATA : { "street":"4bvd NY-city" } -> will update the given fields of the house ressource find by its {id}

DELETE /rest/houses/{id} DATA : none -> will delete the house ressource find by its id.

There is too much things to know about restfull API that i can't give you all the keys. But try to find some good articles on the subjects such as :

http://www.restapitutorial.com/index.html

Not sure if this answer your question, but i hope it'll help you.

EDIT 1 :

Since i have to add some point about a restfull way to give some complicated action i'll give you the restfull url way to go.

In a restful world (extremely rare) you know only one entry point of your rest API let say this :

GET /rest/

This uri will respond you will all the services that the api can provide Exemple :

{
 "resources":"/rest/ressources",
 "apiInfo" : "/rest/api/info"
}

To get your ressources informations you'll follow the link

 GET response.resources

I may respond something like :

{
 "houses":"/rest/ressources/houses/",
 "cars"  :"/rest/ressources/cars"
}

Now we want the houses

GET response.houses

Response :

 {
  "fields":[{
    "constructionYear","street"
   }],
  "search":"/rest/houses"
  "create":"/rest/houses"
 }

etc... And at this place you can add some non restful endpoints. In a restful way. This action will be hold by a restful resource. Somes API that are using this kind of great Restful.

Standard Rest API : https://developers.soundcloud.com/docs/api/reference#users

Restful API : https://www.salesforce.com/us/developer/docs/api_rest/

Upvotes: 2

JotaBe
JotaBe

Reputation: 39025

The question is that the Web API infrastructure must have a way to choose one of the possible methods.

One way is changing the Web API route configuration, including an /{action}/ segment. If you do so it will work exactly like MVC, and you have to always include the action name.

The other way is making the received parameters different in each method, so that the Web API infrastructure can discover which method you're trying to invoke. You can read this answer I've written today for a similar question: How can I add multiple Get actions with different input params when working RESTFUL?.

As a final comment in that answer I say that the parameters can be also discerned by using route contraints.

The first solution of having to include the action name in all invocation is not RESTful, but do you need or prefer it to be RESTful for any particular reason?

Upvotes: 0

Related Questions