Several things are mixed up in your question. First, the technical views you use and second the way you interpret answers.
1) The views
That's a quick one. The view you use by sending data to /api-auth/login/
it DRF's Login view for the browsable API. This view, which is actually the one that ships with Django's auth
app (django.contrib.auth.views.login
) assumes it is dealing with a user, browsing the API manually.
That is: calling it with GET
builds an empty html form, sending back the form with POST
will trigger form validation, which can end up either in the form being redisplayed (200 Ok with a document included), or a redirection to be sent back (302 Found with empty content).
This is why your data is empty: the server sends an HTML document, while your angular probably tried to parse some JSON object.
The form view you use is absolutely not intended to be called from a script. This can be done, but you need to handle the result accordingly, which means analyzing the returned html page to look for error messages. Messy.
You should build your own login view if you want to access it from script easily.
2) Document vs request
You are dealing with two separate levels of semantics here.
- the meaning of the request.
- the meaning of the document enclosed in the request.
HTTP error codes are meaningful in the context of the request. They happen at a lower level. For instance, returning 401 code means “valid authentication credentials are required before performing this request”.
So here, that basically would mean “you must have valid authentication credentials before I process your login request”.
It could make sense, but only in a context where you have two layers of authentication. You would need to have authentication credentials valid for the first layer before it lets your second-layer-login-request through. In this case, you could get an 401 if you try to login with the second layer while not recognized by the first.
So, how does REST fit in?
The concept of REST, when applied to HTTP, is to try to match the request-level semantics and the document-level semantics. It fits particularly well because every REST concept has a matching HTTP verb, HTTP is cacheable, client-server, ... and... stateless.
Stateless means neither HTTP nor REST have the concept of logging in. Logging in is an abstraction, which usually means we use a workflow that looks like this:
- we authenticate to some endpoint (login/password, challenge, oauth, whatever).
- the endpoint returns some authorization token
- we send the authorization token with every next request to the server.
But truth is, every single request has to be authorized by the server. That is, the server will always start by authorizing the request, before looking at what's inside. If this step fails, 401 is an adequate response.
Except step #1. This request does not have the authorization step. It must be processed, the login/password must be retrieved and checked, and depending on the result, the server may decide to send back an authorization token.
So, what error codes would be appropriate if it chooses not to? Well, there are several you may choose from:
- 200 Ok. The login request was successfully handled and yielded an error message, here is a document with the result. Your script would then read the document (could be a JSON object for instance) to see if it has errors or an authorization token.
- 204 No Content. The login request was successfully handled, but yielded nothing and certainly no authorization token. Odd choice, but correct.
- 400 Bad request. The login request was not handled successfully.
Only sure thing is, 401 is not an option. 401 would mean you were not allowed to attempt to login. Not that the login failed.