How to authenticate API calls and use conditional logic to obtain the token only when required? #2316
-
I've got a question regarding some logic flow, that I'm trying to figure out: I have tasks which interact with an API. In order to use the API, I have another task to login and request an auth token from a different API, which I store in notes. In the main set of API tasks, I want to be able to use this logic:
I see that I can almost do that, but it doesn't appear I can call a Task from another Task. Also, I'd like to expand on this by saying:
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
To solve it, you'll need a conditional statement to Let's assume that the structure of your interface MyNotes {
authToken: string;
// ... other notes
} And that the authentication API returns a response like this: interface AuthResponse {
token: string;
} You can create a task to fetch and remember the auth token like so: import { Task, notes } from '@serenity-js/core'
import { Send, GetRequest, LastResponse } from '@serenity-js/assertions'
const ObtainAuthToken = () =>
Task.where(`#actor obtains the authentication token`,
Send.a(GetRequest.to('https://login.mycompany.com/')),
notes<MyNotes>().set('authToken', LastResponse.body<AuthResponse>().token),
) To then make performing the above task conditionally based on whether the import { Task, Check, notes } from '@serenity-js/core'
import { isTr, isPresent, not } from '@serenity-js/assertions'
const ObtainAuthTokenIfNeeded = () =>
Task.where(`#actor obtains the authentication token if needed`,
Check.whether(notes<MyNotes>().get('authToken'), not(isPresent()))
.andIfSo(ObtainAuthToken()),
) You can then take it further to introduce import { Task, Check, notes } from '@serenity-js/core'
import { isPresent, not } from '@serenity-js/assertions'
const ObtainAuthTokenIfNeeded = (forceRefresh: boolean = false) =>
Task.where(`#actor obtains the authentication token if needed`,
Check.whether(forceRefresh, isTrue())
.andIfSo(ObtainAuthToken()),
Check.whether(notes<MyNotes>().get('authToken'), not(isPresent()))
.andIfSo(ObtainAuthToken()),
) From here, you can design your other API-related tasks to first call However, a cleaner approach would be to introduce another task to import { Task, q } from '@serenity-js/core'
import { ChangeApiConfig } from '@serenity-js/rest'
const base64 = (token: string) =>
Buffer.from(apiToken).toString('base64')
const AuthenticateApiCalls = () =>
Task.where(`#actor authenticates API calls`,
ObtainAuthTokenIfNeeded(),
ChangeApiConfig.setHeader(
'Authorization',
q`Bearer ${ notes<MyNotes>().get('authToken').as(base64) }`
)
) Hope this helps! |
Beta Was this translation helpful? Give feedback.
To solve it, you'll need a conditional statement to
Check
and an expectation that the token is not already present.Let's assume that the structure of your
notes()
is defined as follows:And that the authentication API returns a response like this:
You can create a task to fetch and remember the auth token like so: