Closed davidcr01 closed 1 year ago
The API service has been created in the services
folder. It looks like:
export class ApiService {
private readonly baseURL = 'http://localhost:8080'
constructor(private http: HttpClient) { }
login(credentials: any): Observable<any> {
const url = `${this.baseURL}/api-token-auth/`;
return this.http.post(url, credentials);
}
createPlayer(userData: any): Observable<any> {
const url = `${this.baseURL}/api/players/`;
const body = { user: userData };
return this.http.post(url, body);
}
createUser(userData: any): Observable<any> {
let url = `${this.baseURL}/api/users/`;
return this.http.post(url, userData);
}
The baseURL is defined, and also the methods supported by the backend. In this way, if an URL changes, it is only necessary to change it in this file and not in every place an URL is used.
This is a good practice of clean code and integrity. All tests have been passed creating and logging users.
Now, for example, to login the user we use the following code snippet:
login() {
const credentials = {
username: this.loginForm.get('username').value,
password: this.loginForm.get('password').value,
}
this.apiService.login(credentials).subscribe(
async (response) => {
// Store the token in the local storage
this.errorMessage = ''
const encryptedToken = this.encryptionService.encryptData(response.token);
await this.storageService.setAccessToken(encryptedToken);
this.router.navigateByUrl('');
},
(error) => {
console.error('Log in error', error);
this.errorMessage = 'Provided credentials are not correct'
}
);
Notice the this.apiService.login()
method is used.
Notice that it is necessary to import this service in the necessary pages, and also declare it as a provider in the name.module.ts
file.
A little fix has been added to check if the token is expired also when using the api-token-auth
path. Before, a token could be expired and it won't be removed until an API call was done with the token. So, it could be possible that a user with an expired token tried to log into the application, and could be redirected again to the login page due to the expired token.
By this way, the expiration is also checked when using the URL to obtain tokens. This has been performed by implementing the token view:
class CustomObtainAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
if not created and token.created < timezone.now() - timedelta(seconds=settings.TOKEN_EXPIRED_AFTER_SECONDS):
# Token expired, generate a new one
token.delete()
token = Token.objects.create(user=user)
# Serialize the token along with any other data you want to include in the response
response_data = {
'token': token.key
}
return Response(response_data, status=status.HTTP_200_OK)
Is similar to the middleware defined in #15. Now, the token expiration is checked when returning it and when using it.
Now, instead of using:
path('api-token-auth/', ObtainAuthToken.as_view())
we must use:
from djapi.views import CustomObtainAuthToken
....
path('api-token-auth/', CustomObtainAuthToken.as_view())
Description
In the frontend, instead of calling the API URLs directly, it would be great to group all the API calls into a service, and use that service.