Skip to content
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ Each one of them encapsulates the operations related to it (like listing, updati

### Forms

#### `forms.list({ page: 1, pageSize = 10, search = '' })`
#### `forms.list({ page: 1, pageSize = 10, search = '', page })`
- Get a list of your typeforms
- Returns a list of typeform with the payload [refenced here](https://developer.typeform.com/create/reference/retrieve-forms/).
- Returns a list of typeform with the payload [referenced here](https://developer.typeform.com/create/reference/retrieve-forms/).

#### `forms.get({ uid })`
- Get a typeform by UID
- Returns a typeform with the payload [refenced here](https://developer.typeform.com/create/reference/retrieve-form/).
- Returns a typeform with the payload [referenced here](https://developer.typeform.com/create/reference/retrieve-form/).

#### `forms.update({ uid, data = {}, override = false })`
- Get a typeform by UID
- Returns a typeform with the payload [refenced here](https://developer.typeform.com/create/reference/retrieve-form/).
- Returns a typeform with the payload [referenced here](https://developer.typeform.com/create/reference/retrieve-form/).

#### `forms.delete({ uid })`

Expand Down Expand Up @@ -141,16 +141,16 @@ Each one of them encapsulates the operations related to it (like listing, updati
#### `themes.list({ page, pageSize })`
- Gets your themes collection
- `page`: default `1`
- `page_size: default `10`
- `pageSize: default `10`

#### `themes.get({ id })`
- Gets a theme for the given ID

#### `themes.create({ background, colors, font, has_transparent_button, name })`
#### `themes.create({ background, colors, font, hasTransparentButton, name })`
- Creates a theme with the given configuration
- See more details of the payload in [the documentation](https://developer.typeform.com/create/reference/create-theme/)

#### `themes.update({ background, colors, font, has_transparent_button, name })`
#### `themes.update({ background, colors, font, hasTransparentButton, name })`
- Creates a theme with the given configuration
- See more details of the payload in [the documentation](https://developer.typeform.com/create/reference/update-theme/)

Expand All @@ -162,7 +162,7 @@ Each one of them encapsulates the operations related to it (like listing, updati
#### `workspaces.list({ page, pageSize, search })`
- Gets your workspaces
- `page`: default `1`
- `page_size: default `10`
- `pageSize: default `10`
- `search`: search a workspace that partially matches the search string

#### `workspaces.get({ id })`
Expand Down Expand Up @@ -190,7 +190,7 @@ Each one of them encapsulates the operations related to it (like listing, updati

### Responses

#### `responses.list({ uid, page_size, since, until, after, before, completed, sort, query, fields })`
#### `responses.list({ uid, pageSize, since, until, after, before, completed, sort, query, fields })`
- List responses from the given ID
- `uid`: typeform UID
- For parameter details check [the documentation](https://developer.typeform.com/responses/reference/retrieve-responses/)
Expand Down
6 changes: 5 additions & 1 deletion src/create-client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* globals fetch */
import 'isomorphic-fetch'
import { API_BASE_URL } from './constants'
import { buildUrlWithParams } from './utils';

export const clientConstructor = ({ token, ...options }) => {
return {
Expand All @@ -9,9 +10,12 @@ export const clientConstructor = ({ token, ...options }) => {
url,
data,
headers: argsHeaders = {},
params,
...otherArgs
} = args

const requestUrl = buildUrlWithParams(`${API_BASE_URL}${url}`, params)

const {
headers = {}
} = options
Expand All @@ -21,7 +25,7 @@ export const clientConstructor = ({ token, ...options }) => {
...otherArgs
}

return fetch(`${API_BASE_URL}${url}`, {
return fetch(requestUrl, {
...requestParameters,
body: JSON.stringify(data),
headers: {
Expand Down
11 changes: 7 additions & 4 deletions src/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ export default http => ({
}
})

const getForms = (http, { page, pageSize, search } = {}) => {
const getForms = (http, { page, pageSize, search, workspaceId } = {}) => {
return http.request({
method: 'get',
url: `/forms`,
page,
page_size: pageSize,
search
params: {
page,
page_size: pageSize,
search,
workspace_id: workspaceId
}
})
}

Expand Down
22 changes: 12 additions & 10 deletions src/responses.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const getResponses = (
http,
{
uid,
page_size,
pageSize,
since,
until,
after,
Expand All @@ -20,14 +20,16 @@ const getResponses = (
return http.request({
method: 'get',
url: `/forms/${uid}/responses`,
page_size,
since,
until,
after,
before,
completed,
sort,
query,
fields
params: {
page_size: pageSize,
since,
until,
after,
before,
completed,
sort,
query,
fields
}
})
}
16 changes: 8 additions & 8 deletions src/themes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ export default http => ({
update: args => updateTheme(http, args)
})

const getThemes = (http, { page, page_size } = {}) => {
const getThemes = (http, { page, pageSize } = {}) => {
return http.request({
method: 'get',
url: '/themes',
params: {
page,
page_size
page_size: pageSize
}
})
}
Expand All @@ -28,9 +28,9 @@ const getTheme = (http, { id }) => {

const createTheme = (
http,
{ background, colors, font, has_transparent_button, name }
{ background, colors, font, hasTransparentButton, name }
) => {
//check if required properties are defined
// check if required properties are defined
if ([name, font, colors].includes(undefined)) {
throw `Please add the required fields`
}
Expand All @@ -45,7 +45,7 @@ const createTheme = (
background,
colors,
font,
has_transparent_button,
has_transparent_button: hasTransparentButton,
name
})
}
Expand All @@ -59,9 +59,9 @@ const deleteTheme = (http, { id }) => {

const updateTheme = (
http,
{ id, background, colors, font, has_transparent_button, name }
{ id, background, colors, font, hasTransparentButton, name }
) => {
//check if required properties are defined
// check if required properties are defined
if ([name, font, colors].includes(undefined)) {
throw `Please add the required fields`
}
Expand All @@ -76,7 +76,7 @@ const updateTheme = (
background,
colors,
font,
has_transparent_button,
has_transparent_button: hasTransparentButton,
name
})
}
9 changes: 9 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ export const createMemberPatchQuery = ({ members, operation }) => {
}
}))
}

export const buildUrlWithParams = (url, params = {}) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another approach could be to filter out the falsy values first:

export const buildUrlWithParams = (url, params = {}) => {
  const queryParams = Object.keys(params)
    .filter((k) => params[k])
    .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
    .join('&')
   return queryParams ? `${url}?${queryParams}` : url
}

Copy link
Contributor Author

@jepser jepser Sep 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because filter and map will iterate over the values twice, and reduce will do it only once, said that your solution looks more readable and since the parameters won't be more than 10 elements, I will implement your suggestion, thanks :)

const queryParams = Object.keys(params)
.filter((k) => params[k] !== undefined && params[k] !== null)
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
.join('&')

return queryParams ? `${url}?${queryParams}` : url
}
12 changes: 6 additions & 6 deletions src/workspaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export default http => ({
removeMembers: args => removeMembers(http, args)
})

const getWorkspaces = (http, { search, page, page_size } = {}) => {
const getWorkspaces = (http, { search, page, pageSize } = {}) => {
return http.request({
method: 'get',
url: '/workspaces',
params: {
page,
page_size,
page_size: pageSize,
search
}
})
Expand Down Expand Up @@ -83,17 +83,17 @@ const deleteWorkspace = (http, { id }) => {
})
}

const getWorkspaceForms = (
export const getWorkspaceForms = (
http,
{ id, from_id, page, page_size } = {}
{ id, fromId, page, pageSize } = {}
) => {
return http.request({
method: 'get',
url: `/workspaces/${id}/forms`,
params: {
page,
page_size,
from_id
page_size: pageSize,
from_id: fromId
}
})
}
19 changes: 18 additions & 1 deletion tests/unit/forms.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,27 @@ const formsRequest = forms(http)

test('get all forms has the correct method and path', () => {
formsRequest.list()
expect(fetch.mock.calls[0][0]).toBe(`${API_BASE_URL}/forms`)

const url = fetch.mock.calls[0][0].split('?')
expect(url[0]).toBe(`${API_BASE_URL}/forms`)
expect(fetch.mock.calls[0][1].method).toBe('get')
})

test('paramters are sent correctly', () => {
formsRequest.list({
page: 2,
pageSize: 10,
search: 'hola',
workspaceId: 'abc'
})
const url = fetch.mock.calls[0][0].split('?')
const params = new URLSearchParams(url[1])
expect(params.get('page')).toBe('2')
expect(params.get('page')).toBe('2')
expect(params.get('page')).toBe('2')
expect(params.get('page')).toBe('2')
})

test('getForm sends the correct UID', () => {
formsRequest.get({ uid: 'abc123' })
expect(fetch.mock.calls[0][0]).toBe(`${API_BASE_URL}/forms/abc123`)
Expand Down
17 changes: 13 additions & 4 deletions tests/unit/responses.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ beforeEach(() => {
fetch.mockResponse(JSON.stringify({}))
})

const http = clientConstructor({
token: '123'
})

const responsesRequest = responses(http)

test('List responses has the correct path and method', () => {
const http = clientConstructor({
token: '123'
})
const responsesRequest = responses(http)
responsesRequest.list({ uid: 2 })
expect(fetch.mock.calls[0][1].method).toBe('get')
expect(fetch.mock.calls[0][0]).toBe(`${API_BASE_URL}/forms/2/responses`)
})

test('List responses with the given filters', () => {
responsesRequest.list({ uid: 2, pageSize: 15, after: '12345' })
const params = (new URL(fetch.mock.calls[0][0])).searchParams
expect(params.get('page_size')).toBe('15')
expect(params.get('after')).toBe('12345')
})
7 changes: 4 additions & 3 deletions tests/unit/themes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ test('Get themes has the correct path', () => {
})

test('Get themes has the correct parameters', () => {
themesRequest.list({ page: 3, page_size: 15 })
expect(fetch.mock.calls[0][1].params.page).toBe(3)
expect(fetch.mock.calls[0][1].params.page_size).toBe(15)
themesRequest.list({ page: 3, pageSize: 15 })
const params = (new URL(fetch.mock.calls[0][0])).searchParams
expect(params.get('page')).toBe('3')
expect(params.get('page_size')).toBe('15')
})

test('Get themes has the correct path', () => {
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { buildUrlWithParams } from '../../src/utils'

test('the url reminds the same if no parameter passed', () => {
const url = 'http://typeform.com'
expect(buildUrlWithParams(url)).toBe(url)
})

test('the url has a query string if parameters are passed', () => {
const url = 'http://typeform.com'
const params = {
a: '1',
b: '2'
}
expect(buildUrlWithParams(url, params)).toBe('http://typeform.com?a=1&b=2')
})

test('parameters should be enconded', () => {
const url = 'http://typeform.com'
const params = {
a: '@1',
b: '#2'
}
expect(buildUrlWithParams(url, params)).toBe('http://typeform.com?a=%401&b=%232')
})

test('undefined values for parameter will be skipped', () => {
const url = 'http://typeform.com'
const params = {
a: '@1',
b: undefined
}
expect(buildUrlWithParams(url, params)).toBe('http://typeform.com?a=%401')
})

test('falsy values should be passed', () => {
const url = 'http://typeform.com'
const params = {
a: '0',
b: 0,
c: null
}
expect(buildUrlWithParams(url, params)).toBe('http://typeform.com?a=0&b=0')
})
14 changes: 13 additions & 1 deletion tests/unit/workspaces.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,24 @@ const http = clientConstructor({
})
const workspacesRequest = workspaces(http)


test(`Get workspaces has the correct path`, () => {
workspacesRequest.list()
expect(fetch.mock.calls[0][0]).toBe(`${API_BASE_URL}/workspaces`)
})

test(`Get workspaces has the correct query parameters`, () => {
workspacesRequest.list({
search: 'hola',
page: 2,
pageSize: 10
})

const params = new URL(fetch.mock.calls[0][0]).searchParams
expect(params.get('search')).toBe('hola')
expect(params.get('page')).toBe('2')
expect(params.get('page_size')).toBe('10')
})

test(`Get specific workscape has the correct path and method`, () => {
workspacesRequest.get({ id: 2 })
expect(fetch.mock.calls[0][1].method).toBe(`get`)
Expand Down