Skip to content

Commit

Permalink
wip: use common http
Browse files Browse the repository at this point in the history
  • Loading branch information
mtuchi committed Oct 27, 2023
1 parent 8eb143d commit fe8effb
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 112 deletions.
71 changes: 43 additions & 28 deletions packages/template/src/Adaptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,47 @@ import {
execute as commonExecute,
composeNextState,
} from '@openfn/language-common';
import { expandReferences } from '@openfn/language-common/util'
import { request } from './Utils';

import {
request as commonRequest,
expandReferences,
} from '@openfn/language-common/util';

import { makeBasicAuth } from './Utils';

export function request(method, path, params, callback) {
return state => {
const [resolvedPath, resolvedParams] = expandReferences(
state,
path,
params
);

const { username, password, baseUrl } = state.configuration;

let { headers = { 'content-type': 'application/json' } } = resolvedParams;

headers['Authorization'] = makeBasicAuth(username, password);

const options = {
...resolvedParams,
headers,
baseUrl,
};

return commonRequest(method, resolvedPath, options)
.then(response => {
const { method, url, body, code, duration } = response;
console.log(method, url, '-', code, 'in', duration + 'ms');

return {
...composeNextState(state, body),
response,
};
})
.then(nextState => callback?.(nextState) ?? nextState);
};
}
/**
* Execute a sequence of operations.
* Wraps `language-common/execute` to make working with this API easier.
Expand Down Expand Up @@ -44,33 +82,9 @@ export function execute(...operations) {
* @returns {Operation}
*/
export function create(resource, data, callback) {
return state => {
const [resolvedResource, resolvedData] = expandReferences(state, resource, data);

const { baseUrl, username, password } = state.configuration;

const url = `${baseUrl}/api/${resolvedResource}`;
const auth = { username, password };

const options = {
auth,
body: resolvedData,
method: 'POST',
};

return request(url, options).then(response => {
const nextState = {
...composeNextState(state, response.data),
response,
};
if (callback) return callback(nextState);
return nextState;
});
};
return request('POST', `/api/${resource}`, { body: data }, callback);
}

export { request } from './Utils';

// TODO: Decide which functions to publish from @openfn/language-common
export {
dataPath,
Expand All @@ -80,7 +94,8 @@ export {
field,
fields,
fn,
http,
chunk,
parseCsv,
lastReferenceValue,
merge,
sourceValue,
Expand Down
31 changes: 2 additions & 29 deletions packages/template/src/Utils.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,6 @@
// TODO: Determine how to authenticate for the target API
function makeAuthHeader(auth) {
const { username, password } = auth;
export function makeBasicAuth(username, password) {
const buff = Buffer.from(`${username}:${password}`);
const credentials = buff.toString('base64');
return { Authorization: `Basic ${credentials}` };
}

export async function request(url, options) {
const { auth } = options;
delete options.auth;

const response = await fetch(url, {
...options,
headers: {
'content-type': 'application/json',
...makeAuthHeader(auth),
},
});

// TODO: Handle errors based on the behavior of the target API
if (response.status === 404) {
throw new Error('Page not found');
} else if (response.status === 500) {
throw new Error('Server error');
} else if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

// TODO: Extract data from response based on the target API
const data = await response.json();
return data;
return `Basic ${credentials}`;
}
74 changes: 62 additions & 12 deletions packages/template/test/Adaptor.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { expect } from 'chai';
import { execute, create, dataValue } from '../src/Adaptor.js';

import MockAgent from './mockAgent.js';
import { setGlobalDispatcher } from 'undici';
import { enableMockClient } from '@openfn/language-common/util';

setGlobalDispatcher(MockAgent);
const testServer = enableMockClient('https://www.example.com');

describe('execute', () => {
it('executes each operation in sequence', done => {
Expand Down Expand Up @@ -39,10 +38,45 @@ describe('execute', () => {
});

describe('create', () => {
before(() => {
testServer
.intercept({
path: '/api/patients',
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: 'Basic aGVsbG86dGhlcmU=',
},
})
.reply(
200,
{ id: 7, fullName: 'Mamadou', gender: 'M' },
{
headers: { 'content-type': 'application/json' },
}
);
testServer
.intercept({
path: '/api/noAccess',
method: 'POST',
})
.reply(
404,
{
message: 'Not found',
status: 'error',
code: 404,
},
{
headers: { 'content-type': 'application/json' },
}
);
});

it('makes a post request to the right endpoint', async () => {
const state = {
configuration: {
baseUrl: 'https://fake.server.com',
baseUrl: 'https://www.example.com',
username: 'hello',
password: 'there',
},
Expand All @@ -69,7 +103,7 @@ describe('create', () => {
it('throws an error for a 404', async () => {
const state = {
configuration: {
baseUrl: 'https://fake.server.com',
baseUrl: 'https://www.example.com',
username: 'hello',
password: 'there',
},
Expand All @@ -81,24 +115,40 @@ describe('create', () => {
return error;
});

expect(error.message).to.eql('Page not found');
expect(error.message).to.eql('POST /api/noAccess - 404 Not Found');
});

it('handles and throws different kinds of errors', async () => {
it.skip('handles and throws different kinds of errors', async () => {
testServer
.intercept({
path: '/api/!@#$%^&*',
method: 'POST',
})
.reply(
500,
{
message: 'Server error',
status: 'error',
code: 500,
},
{
headers: { 'content-type': 'application/json' },
}
);
const state = {
configuration: {
baseUrl: 'https://fake.server.com',
baseUrl: 'https://www.example.com',
username: 'hello',
password: 'there',
},
};

const error = await execute(
create('!@#$%^&*', { name: 'taylor' })
)(state).catch(error => {
const error = await execute(create('!@#$%^&*', { name: 'taylor' }))(
state
).catch(error => {
return error;
});

expect(error.message).to.eql('Server error');
});
});
43 changes: 0 additions & 43 deletions packages/template/test/mockAgent.js

This file was deleted.

0 comments on commit fe8effb

Please sign in to comment.