Skip to content

Instantly share code, notes, and snippets.

@janbaykara
Last active February 26, 2024 14:39
Show Gist options
  • Save janbaykara/53d84ad8b7a40123d5cb6e23e6babed5 to your computer and use it in GitHub Desktop.
Save janbaykara/53d84ad8b7a40123d5cb6e23e6babed5 to your computer and use it in GitHub Desktop.
Action Network ORM for Typescript
import fetch, { RequestInfo, RequestInit, Response } from 'node-fetch'
import {merge} from 'lodash'
import { BuilderFunc, ODataFilterBuilder } from 'ts-odata-filter'
import * as queryString from 'query-string'
import { Person, PersonSignupHelper } from '@civix/osdi-types';
const crytalise = (init: RequestInit) => {
if (init.body) {
init.body = JSON.stringify(init.body)
}
return init
}
export default (apiKey: string) => {
if (!apiKey || typeof apiKey !== 'string') {
throw new Error("Please provide an Action Network API Key")
}
const actionNetworkInit = {
headers: {
'Content-Type': 'application/json',
'OSDI-API-Token': apiKey
}
}
const request = async <T>(url: RequestInfo, init?: Omit<RequestInit, 'body'> & { body?: any }): Promise<T> => {
const res = await fetch(url, crytalise(merge({}, actionNetworkInit, init)))
return res.json()
}
const person = {
//
create: (data: PersonSignupHelper) => request<Person>(
`https://actionnetwork.org/api/v2/people`,
{ method: 'POST', body: data }
),
//
retrieve: (id: string) => request<Person>(
`https://actionnetwork.org/api/v2/people/${id}`,
{ method: 'GET' }
),
//
// Alternative: https://www.npmjs.com/package/filter-odata
list: async ({ filter, quantity, page }: ListArgs<PersonFilter>) => {
const query: queryString.ParsedQuery<any> = {}
if (quantity) {
query.per_page = quantity
}
if (page) {
query.page = page
}
if (filter) {
query.filter = ODataFilterBuilder.build(filter).getString()
}
const response = await request<OSDIResponse<{ 'osdi:people': Person[] }>>(
queryString.stringifyUrl({
url: `https://actionnetwork.org/api/v2/people?`,
query
}),
{ method: 'GET' }
)
return { items: response?._embedded["osdi:people"] || [], page: response?.page, response }
}
//
}
return {
request,
person
}
}
interface ListArgs<T> {
/**
* Maximum 25
* https://actionnetwork.org/docs/v2/
*/
page?: number
quantity?: number
filter?: BuilderFunc<T>
}
interface PersonFilter {
identifier: string
created_date: Date
modified_date: Date
email_address?: string
family_name?: string
given_name?: string
region?: string
postal_code?: string
}
export interface OSDIResponse<T> {
per_page: number;
page: number;
_links: Links;
_embedded: T
}
export interface Embedded {
"osdi:people": any[];
}
export interface Links {
next: Next;
"osdi:people": Next[];
curies: Cury[];
self: Next;
}
export interface Cury {
name: string;
href: string;
templated: boolean;
}
export interface Next {
href: string;
}
const actionnetwork = ActionNetwork(process.env.ACTIONNETWORK_API_KEY)
const getManyPeople = async (quantity: number) => await new Promise((resolve) => {
let people = []
let page = 0
const fetchMore = async () => {
const startTime = performance.now()
page = page + 1
const batch = await actionnetwork.person.list({ page })
people = people.concat(batch?.items)
console.log(batch?.page, quantity, people.length, batch?.items.length)
if (people.length >= quantity || batch?.items?.length === 0) {
return resolve(people)
} else {
setTimeout(() => {
fetchMore()
}, Math.max(0, 250 - (performance.now() - startTime)))
}
}
fetchMore()
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment