Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

JavaScript Model validation error when using Fetch or Axios despite returning a status 200 in the backend?

accol

Coder
Thank you to anyone who reads and replies to this. I do not know what I'm doing wrong by this point.

I've been trying to connect the React.js frontend to my ASP.NET Core backend. I've tried both Fetch and Axios and I've been getting the same error each time, however it doesn't make sense to me because in Swagger, when I pass in the same username and password, it's successful.

Below is what Response shows under the network tab.
JSON:
{
    "type": "RFC 9110: HTTP Semantics",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {
        "password": [
            "The password field is required."
        ],
        "username": [
            "The username field is required."
        ]
    },
    "traceId": "00-3e924f01d520f60adedb593b857e0cd1-accd29f9df16d4bd-00"
}
I checked and it seems like the username and password are being passed according to the Payload.
{username: "OMORI", password: "U_k!ll3d_h3r"}
password: "U_k!ll3d_h3r"
username: "OMORI"
Code:
JavaScript:
const onLoginButtonClick = async () => {
    if (!onCheckValidInput()) {
        return;
    }

    const response = await axios.post('/api/Authentication/Login', {
        username: username,
        password: password
    }).catch(err => alert(err));
}

This is the result when I tried using Swagger and it also logs in the console so I'm not sure why the backend wouldn't be validating the model.

1710602233318.png

Below is the controller code.
C#:
namespace OMORI.Server.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthenticationController : ControllerBase
    {
        private readonly AppDBContext _context;
        private readonly ILogger<AuthenticationController> _logger;

        public AuthenticationController(AppDBContext context, ILogger<AuthenticationController> logger)
        {
            _context = context;
            _logger = logger;
        }

        // POST: api/Authentication/Login
        [HttpPost("Login")]
        public async Task<ActionResult<User>> Login(string username, string password)
        {
            var user = await _context.User.FirstOrDefaultAsync(u => u.username == username);

            if (user == null)
                return NotFound();
           // I don't think you can convert a byte array like that but I just wanted to log and see if the information's being passed in and out to the console
            _logger.LogInformation(
                "======================" +
                "\nUsername: " + username +
                "\nPassword: " + password +
                "\n" +
                "\nUser ID: " + user.userID.ToString() +
                "\nHashed password: " + user.passwordHash +
                "\nSalt: " + user.passwordSalt.ToString() +
                "\n=====================");

            if (AuthenticationService.VerifyPassword(password, user.passwordHash, user.passwordSalt))
                return Ok(user);
          
            return NotFound();
        }
    }
}

The model that it uses.
C#:
public class User
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int userID { get; set; }
    [Required, Column(TypeName = "nvarchar(max)")]
    public string username { get; set; }
    [Required, Column(TypeName = "nvarchar(max)")]
    public string passwordHash { get; set; }
    [Required, Column(TypeName="varbinary(max)")]
    public byte[] passwordSalt {get;set;}
}

I've also made sure that inside of vite.config.js that I set the proxy to be /api as well for development.
JavaScript:
// https://vitejs.dev/config/
export default defineConfig({
    plugins: [plugin()],
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url))
        }
    },
    server: {
        proxy: {
            '/api': {
                target: 'https://localhost:7095/',
                secure: false
            }
        },
        port: 5173,
        https: {
            key: fs.readFileSync(keyFilePath),
            cert: fs.readFileSync(certFilePath),
        }
    }
})

Another thing to note is that when I tried to debug and put breakpoints at various parts of the Login function, when I click on Log In button, it never reaches that function either. I don't know if there's something wrong with the controller itself because according to ASP.NET Core REST API and ModelState.IsValid check,
In an ASP.NET Core REST API, there is no need to explicitly check if the model state is Valid. Since the controller class is decorated with the [ApiController] attribute, it takes care of checking if the model state is valid and automatically returns 400 response along the validation errors.
 
A lot of stuff here I don't know anything about - React, ASP.Net, Axios, Swagger ... I have only gotten as far as using vanilla JS with XmlHTTPRequest against a PHP backend. I'd take my cue from the fact it works with Swagger. Actually that seems to be using the good old cUrl command, the Payload data being username=OMORI&password=U_k!ll3d_h3r. At last something I do understand :) So you need to make sure that is also what your Axios solutions posts. Do you see any difference in the Payload for the two methods ?

You seem to suggest that it never reaches the Logon function on the server. In that case how can you be getting back the JSON response you showed, saying username and password are required ? Or is it just that you are not hitting the breakpoint as expected ?
 
A lot of stuff here I don't know anything about - React, ASP.Net, Axios, Swagger ... I have only gotten as far as using vanilla JS with XmlHTTPRequest against a PHP backend. I'd take my cue from the fact it works with Swagger. Actually that seems to be using the good old cUrl command, the Payload data being username=OMORI&password=U_k!ll3d_h3r. At last something I do understand :) So you need to make sure that is also what your Axios solutions posts. Do you see any difference in the Payload for the two methods ?

You seem to suggest that it never reaches the Logon function on the server. In that case how can you be getting back the JSON response you showed, saying username and password are required ? Or is it just that you are not hitting the breakpoint as expected ?
Hey, thanks so much for responding.

Let me go through this one by one, I'm actually pretty new to this myself so I'm also at a loss (I'm an amateur to web app development in general). Hahhaahahhaahh.
Do you see any difference in the Payload for the two methods ?
I don't see anything different in the payload data itself as I showed you they are definitely passing in the username being OMORI and the password being U_k!lled_her, although the difference would be the address the frontend's sending from. localhost:5173 vs localhost:7095 which is the server. I however thought that changing the vite.config.js's proxy to /api would've allowed me to pass in the url starting from /api1710714439748.png

I also tried using Fetch to pass in the full url as well because I thought that might have been the issue
JavaScript:
const response = await fetch('https://localhost:7095/api/Authentication/Login', {
    method: "POST",
    mode: "no-cors",
    headers: {
        "Accept": "application/json",
        "Content-Type": "application/json",
    },
    body: JSON.stringify({
        username: username,
        password: password
    }),
}).catch(err => alert(err));

and got
1710715924926.png
nothing under Preview and Response either, same data in Payload as written in the previous post.

You seem to suggest that it never reaches the Logon function on the server. In that case how can you be getting back the JSON response you showed, saying username and password are required ? Or is it just that you are not hitting the breakpoint as expected ?
I'm not entirely sure if it doesn't reach Login() in the server and that's what I'm concerned about. When I tried using breakpoints it never even touches the first line var user = await _context.User.FirstOrDefaultAsync(u => u.username == username); and wasn't sure how to interpret what's going on.
 
Last edited:
I'm rather out of my depth here too. If the URL's are the same and the payload is the same I'd expect to get the same response. I am confused about these different port numbers, firstly why that is, secondly why the server would even care ? But it looks like you must try and find out what is happening inside the sever code, why it is returning a 400 error or why it says user and password are required while you are actually providing them. I am not familiar with server-side debugging so I have no idea why it's not hitting your breakpoint. I would split that first line in two, just in case the debugger does not think it should break on a var declaration. Otherwise, I would choose to put some logging in your server-side code so I could follow what it is doing. Regarding the 400 error, can you not find some clue in the webserver's logs ?
 
I'm rather out of my depth here too. If the URL's are the same and the payload is the same I'd expect to get the same response. I am confused about these different port numbers, firstly why that is, secondly why the server would even care ? But it looks like you must try and find out what is happening inside the sever code, why it is returning a 400 error or why it says user and password are required while you are actually providing them. I am not familiar with server-side debugging so I have no idea why it's not hitting your breakpoint. I would split that first line in two, just in case the debugger does not think it should break on a var declaration. Otherwise, I would choose to put some logging in your server-side code so I could follow what it is doing. Regarding the 400 error, can you not find some clue in the webserver's logs ?
Ok thank you, I'll try my best to figure it out and come back here...although it's definitely gonna take a while. Will try to break that first line in two first then try to log in the server side code and find the web server's logs. I don't know if it has something to do with the template I used, I just used the React and ASP.NET Core template found inside of Visual Studio as a basis.
 
Back
Top Bottom