Failing at API dev

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,051
Reaction score
17,804
I simply cannot see the problem here. Granted I've been staring at this project for a while now and starting to hard code **** in desperation. Please someone suggest what I have done wrong here! :X3:

In short, the client will simply not send the update request to the API.

1.jpg


2.jpg


3.jpg


4.jpg
 
Strange. Integrated this and it works now. It is definitely something to do with serializing objects to json first.
C#:
string jsonData = JsonConvert.SerializeObject(emp);

HttpContent content = new StringContent(jsonData);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
 
I simply cannot see the problem here. Granted I've been staring at this project for a while now and starting to hard code **** in desperation. Please someone suggest what I have done wrong here! :X3:

In short, the client will simply not send the update request to the API.

1.jpg


2.jpg


3.jpg


4.jpg
What does your EmployeeDto.ToString method look like on the client implementation?
 
I reckon @Barbarian Conan got it right, so I will do some code review instead ;)

  • Remove the [Produces]. If a client wants XML, let them get XML (dotnet core has some built-in converters)
  • Ignore the ID in the PUT body. I don't think it adds much, and in general, PUT replaces an entity's data, but you really should not be updating the ID, which is likely a DB key that makes no sense to update.
  • Extend ControllerBase instead of Controller if you don't need view support.
  • Add [ApiController] attribute if this is a pure API controller, you get some goodies out of the box - https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-5.0#apicontroller-attribute
 
[HttpPut("id")]

client.PostAsync(url, content)

Sample Image

swagger-management-endpoints-img.png


What concerns me a little is that now my swagger doesn't look like that anymore now that I've removed the curly bracers. It still works but it looks different with now just a api/employees/id

Does it make a difference?
 
What concerns me a little is that now my swagger doesn't look like that anymore now that I've removed the curly bracers. It still works but it looks different with now just a api/employees/id

Does it make a difference?
bit of a typo there from @Barbarian Conan, but the lack of braces has no bearing on your original problem. Look at your verbs, specifically what your endpoint expects and which verb your client makes use of.

p.s. you can bring your braces back
 
Normally a PUT route does not include {id}. It implies you are PUTting to a resource that does not yet exist. Sense it does not make
 
I disagree.
In strict terms you POST to /users to create a user and you PUT to /users/{id} to update. PUTs should be idempotent i.e. executing the same PUT request multiple times and get the same result. Executing a POST multiple times results in multiple resources. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

In personal terms, I seldom use PUT and just POST to /users to create a user and POST to /user/{id} to update a user.
 
I disagree.
In strict terms you POST to /users to create a user and you PUT to /users/{id} to update. PUTs should be idempotent i.e. executing the same PUT request multiple times and get the same result. Executing a POST multiple times results in multiple resources. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

In personal terms, I seldom use PUT and just POST to /users to create a user and POST to /user/{id} to update a user.
Front-end framework devs must love you lol
 
I disagree.
In strict terms you POST to /users to create a user and you PUT to /users/{id} to update. PUTs should be idempotent i.e. executing the same PUT request multiple times and get the same result. Executing a POST multiple times results in multiple resources. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

In personal terms, I seldom use PUT and just POST to /users to create a user and POST to /user/{id} to update a user.
What he said
 
I disagree.
In strict terms you POST to /users to create a user and you PUT to /users/{id} to update. PUTs should be idempotent i.e. executing the same PUT request multiple times and get the same result. Executing a POST multiple times results in multiple resources. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

In personal terms, I seldom use PUT and just POST to /users to create a user and POST to /user/{id} to update a user.
This is good advice, I am adopting this. Although its a caveat to see the puts and posts on Swagger I have reached the point now where puts are seldom necessary. Eg. Removing roles from an IdentityUser, was going with a put but realized a post is fine.

Still going flat out with this project. Everything up to now has been building the Admin and Account areas; roles, users, logins, registration, claims etc. Getting the API and MVC to communicate.

MVC side doesnt even used IdentitUser, thats all on the API, and in MVC front end I simply using wrapper classes to handle to posting of and retrieval of information and IdentityResults. Its coming together very nicely. I have promised to upload it to Github once done so I will. At this point I am on the User mvc section, being able to add and remove claims such as "AddRole" or "DeleteUser" all using a simple boolean true or false. Its coming along.
 
I started with all the Identity stuff because I soon realized while learning MVC just how important roles and claims are. Tough to star with but just jumped in the deep end.

Have come a long with these last few weeks from battling with HttpClient :unsure:

Remove all roles from the User (API)

C#:
public class UpdateUserRolesRequest
{
    public string UserId { get; set; }

    public IEnumerable<string> Roles { get; set; }
}

C#:
// POST api/v1/users/remove-from-roles/
[HttpPost(ApiRoutes.Users.RemoveFromRoles)]
public async Task<IActionResult> RemoveFromRoles([FromBody] UpdateUserRolesRequest request)
{
    var user = await _userManager.FindByIdAsync(request.UserId);

    if(user == null)
    {
        return NotFound(new UpdateResponse
        {
            Errors = new[] { "User does not exist!" }
        });
    }

    var result = await _userManager.RemoveFromRolesAsync(user, request.Roles);

    if (!result.Succeeded)
    {
        return BadRequest(new UpdateResponse
        {
            Errors = new[] { result.Errors.ToString()}
        });
    }

    return Json(new { success = true });
}
 
Last edited:
Let’s review the namings.
“RemoveFromRoles” - not a fan of this name. You wouldn’t speak like this.

I assume this endpoint takes in a user ID and a list of roles, and then makes sure that the user with that ID no longer has the given list of roles?

I would define the endpoint as
POST /user/{id}/remove-roles, with the body containing a list of the roles, but the user ID is in the url.
I guess you could also do a DELETE to /user/{id}/roles[/{roleId}] - body containing list of roles OR specifying the role ID to remove in the url.

userManager.RemoveRolesAsync instead of userManager.RemoveFromRolesAsync

I wouldnt use a word like “Update” in isolation in this context. You can see why with a name like “UpdateResponse”. That sounds like a method that updates the HTTP response, but in actual fact it IS your response.
I would maybe rather use “RemoveRolesFromUserResponse”

no need to return that success object. It doesn’t add anything.
Just “return Ok();”
 
I totally get what you saying yes. Will make those changes.
 
no need to return that success object. It doesn’t add anything.
Just “return Ok();”

Oh yeah. The reason I did that is because whether it returns a success or a fail, it still returns as nothing in my MVC Service.

I'll explain. In the below, say I get a success or fail from the API, this section here reflects that response message

var response = await client.PostAsync(methodUrl, content);

However on the next line, it's completely lost. It returns as empty.

var responseAsString = await response.Content.ReadAsStringAsync();

I've tried everything to get it to work but it simply will not read that response in as a string. Something to do with the deserializing. It only works if I pass in a class of a type of that response in this case, IdentityResult.

C#:
public class CreateNewUserResult
{
    public bool Success { get; set; }

    public List<object> Errors { get; set; }
}

C#:
public async Task<T> PostAsync<T>(string methodUrl, object model)
{
    HttpClient client = new HttpClient();

    // Now serialzize the object to json
    string jsonData = JsonConvert.SerializeObject(model);

    // Create a content
    HttpContent content = new StringContent(jsonData);
    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

    // Make a request
    var response = await client.PostAsync(methodUrl, content);
    var responseAsString = await response.Content.ReadAsStringAsync();

    // Deserialize the coming object into a T object
    T obj = JsonConvert.DeserializeObject<T>(responseAsString);

    return obj;
}

Edit: One last thing. This is being consumed by MVC which has support for HttpResponse. What if something completely different needs to consume it. Afaik this is how Angular for eg handles a response.

JavaScript:
this.http
  .get('http://thecatapi.com/api/images/get?format=html&results_per_page=10')
  .map(this.extractData)
  .catch(this.handleError);

private extractData(res: Response) {
   let body = res.text();  // If response is a JSON use json()
   if (body) {
       return body.data || body;
    } else {
       return {};
    }
}
 
Last edited:
This is good advice, I am adopting this. Although its a caveat to see the puts and posts on Swagger I have reached the point now where puts are seldom necessary. Eg. Removing roles from an IdentityUser, was going with a put but realized a post is fine.

Still going flat out with this project. Everything up to now has been building the Admin and Account areas; roles, users, logins, registration, claims etc. Getting the API and MVC to communicate.

MVC side doesnt even used IdentitUser, thats all on the API, and in MVC front end I simply using wrapper classes to handle to posting of and retrieval of information and IdentityResults. Its coming together very nicely. I have promised to upload it to Github once done so I will. At this point I am on the User mvc section, being able to add and remove claims such as "AddRole" or "DeleteUser" all using a simple boolean true or false. Its coming along.
Please don't create an api with put as post, especially if it's publicly visible. There is a reason verbs exist not to mention a proper put, post have differing return codes for absorbtion and processing.
 
Lol yeah. Wtf would you just decide to go against convention and POST for updates? You might think it’s okay now but wait until someone else needs to work on your project or you need a client/server library that expects proper conventions.
 
Top
Sign up to the MyBroadband newsletter
X