Skip to content

Commit

Permalink
feat: use Authorization header for authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
jamacku committed Sep 13, 2024
1 parent 592e41e commit 0a5873b
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 9 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,19 @@ Typesafe access to [Testing Farm's REST API](https://api.dev.testing-farm.io/red
```typescript
import TestingFarmAPI from "testing-farm";

const api = new TestingFarmAPI("https://api.dev.testing-farm.io/v0.1", "api-key");

// Passing api key in data - not recommended
const api = new TestingFarmAPI("https://api.dev.testing-farm.io/v0.1");

await api.about();
```

> [!WARNING]
>
> Passing the API key in request body is deprecated and not recommended. It is better to pass it in the constructor.
> This way the API key will be passed in the request header as part of `Authorization` header.
### List a Test Requests

documentation of - [`GET /requests`](https://api.dev.testing-farm.io/redoc#operation/get_test_requests_v0_1_requests_get)
Expand Down
15 changes: 10 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PublicLink } from './link';
import { ApiKeyLink, PublicLink, TestingFarmLink } from './link';
import { isError } from './util';
import {
About,
Expand Down Expand Up @@ -46,10 +46,15 @@ export {
};

export default class TestingFarmAPI {
private readonly link: PublicLink;

constructor(instance: string) {
this.link = new PublicLink(new URL(instance));
private readonly link: TestingFarmLink;

constructor(instance: string, apiKey?: string) {
// Use PublicLink only for endpoints that don't require authentication
if (!apiKey) {
this.link = new PublicLink(new URL(instance));
} else {
this.link = new ApiKeyLink(new URL(instance), apiKey);
}
}

async requests(filter: RequestsFilter): Promise<Request[]>;
Expand Down
27 changes: 27 additions & 0 deletions src/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,30 @@ export class PublicLink extends TestingFarmLink {
return performRequest(config);
}
}

/**
* Handles authentication using an API key.
*/
export class ApiKeyLink extends TestingFarmLink {
public constructor(
instance: URL,
private readonly apiKey: string
) {
super(instance);
}

protected async request(config: AxiosRequestConfig): Promise<unknown> {
return performRequest({
...config,
headers: {
...(config.headers ?? {}),
// https://api.dev.testing-farm.io/redoc#operation/request_a_new_test_v0_1_requests_post
// OAuth2: OAuth2PasswordBearer
// The API key for authentication.
// Flow type: password
// Token URL: token
Authorization: `Bearer ${this.apiKey}`,
},
});
}
}
4 changes: 2 additions & 2 deletions src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export const requestsFilterSchema = z.object({
export type RequestsFilter = z.infer<typeof requestsFilterSchema>;

export const newRequestSchema = z.object({
api_key: z.any(),
api_key: z.any().optional(),
test: testObjectSchema,
environments: z.array(environmentSchema).optional(),
notification: notificationSchema.optional().nullable(),
Expand Down Expand Up @@ -208,7 +208,7 @@ export const requestSchema = z.object({
export type Request = z.infer<typeof requestSchema>;

export const cancelRequestSchema = z.object({
api_key: z.any(),
api_key: z.any().optional(),
});

export type CancelRequest = z.infer<typeof cancelRequestSchema>;
Expand Down
7 changes: 5 additions & 2 deletions test/integration/cancel-request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ describe('Test Testing Farm DELETE /requests/{request_id}', () => {
});

test.todo('unsafe response', async () => {
const api = new TestingFarmAPI('https://api.dev.testing-farm.io/v0.1');
const api = new TestingFarmAPI(
'https://api.dev.testing-farm.io/v0.1',
'api_key'
);

const response = await api.cancelRequest(
'f053796b-452e-4da2-b4e1-26eb2f3e721f',
{ api_key: 'api_key' },
{},
false
);
expect(response).toBeTypeOf('object');
Expand Down

0 comments on commit 0a5873b

Please sign in to comment.