Normalized responses
The Patreon API returns data in the JSON:API format with the data spread over attributes
, relationships
and included
fields. Using a normalized / simplified response will combine all relationships
with included
data.
Since this format is not the easiest to work, I'd advice to use the normalize, simplified or your own response parsers. Compare the payloads below.
{
"data": {
"type": "campaign",
"id": "id",
"attributes": {
"created_at": "<date>"
},
"relationships": {
"creator": {
"data": {
"type": "user",
"id": "user_id"
}
}
}
},
"included": [
{
"type": "user",
"id": "user_id",
"attributes": {
"full_name": "John Doe"
}
}
]
}
{
"type": "campaign",
"id": "id",
"created_at": "<date>",
"creator": {
"type": "user",
"id": "user_id",
"full_name": "John Doe"
},
"link": "https://patreon.com/api/oauth/v2/campaigns/id"
}
{
"type": "campaign",
"id": "id",
"createdAt": "<date>",
"creator": {
"type": "user",
"id": "user_id",
"fullName": "John Doe"
},
"link": "https://patreon.com/api/oauth/v2/campaigns/id"
}
methods
The simplify
method will both normalize
the response and convert all keys to camelCase. You can also use the simplify
/ normalize
methods by default in the client methods by using client.simplified
/ client.normalized
.
import { simplify, PatreonCreatorClient, QueryBuilder } from 'patreon-api.ts'
declare const client: PatreonCreatorClient
const campaignQuery = QueryBuilder.campaign
.addRelationships(['creator'])
.setAttributes({ campaign: ['created_at'], user: ['full_name'] })
const rawCampaign = await client.fetchCampaign('campaign_id', campaignQuery)
const simplified = simplify(rawCampaign)
console.log(`Campaign by ${simplified.creator.fullName} created at ${simplified.createdAt}`)
const postsQuery = QueryBuilder.campaignPosts
.addRelationships(['campaign'])
.setAttributes({ campaign: ['created_at'], post: ['is_paid', 'title'] })
const campaignPosts = await client.fetchCampaignPosts('campaign_id', postsQuery)
const posts = simplify(campaignPosts)
for (const post of posts.data) {
console.log(`Post ${post.title} is paid: ${post.isPaid}`)
}
import { normalize, PatreonCreatorClient, QueryBuilder } from 'patreon-api.ts'
declare const client: PatreonCreatorClient
const campaignQuery = QueryBuilder.campaign
.addRelationships(['creator'])
.setAttributes({ campaign: ['created_at'], user: ['full_name'] })
const rawCampaign = await client.fetchCampaign('campaign_id', campaignQuery)
const normalized = normalize(rawCampaign)
console.log(`Campaign by ${normalized.creator.full_name} created at ${normalized.created_at}`)
const postsQuery = QueryBuilder.campaignPosts
.addRelationships(['campaign'])
.setAttributes({ campaign: ['created_at'], post: ['is_paid', 'title'] })
const campaignPosts = await client.fetchCampaignPosts('campaign_id', postsQuery)
const posts = normalize(campaignPosts)
for (const post of posts.data) {
console.log(`Post ${post.title} is paid: ${post.is_paid}`)
}
import {
type PatreonClient,
QueryBuilder,
Routes,
Type,
type PatreonQuery,
simplifyFromQuery,
} from 'patreon-api.ts'
export async function fetchPatreonRaw (client: PatreonClient) {
type Query = PatreonQuery<Type.Campaign, 'creator', {
user: ('full_name')[]
}, true>
const query = QueryBuilder.fromParams<Query>(new URLSearchParams({
include: 'creator',
'fields[user]': 'full_name',
}))
// get the campaigns
const campaigns = await client.fetchOauth2(Routes.campaigns(), query)
// or fetch the post(s), member(s), post(s) or current user
const simplified = simplifyFromQuery<Query>(campaigns)
}
If you do not have response typed, you can also use the query type with the simplifyFromQuery
/ normalizeFromQuery
methods to create the same response type.
custom
You can also create a custom payload parser to append certain attributes or modify the request in a different way.
To register a custom parser, use module augmentation for the correct types. Add a key to ResponseTransformMap
with a function that satisfies (res: GetResponsePayload<Query>) => any
.
WARNING
Since I don't know how (or it is not possible) to do module augmentation with generics, response
will be typed as never
. When you create your custom parser, you will be able to see the correct types for response
.
An example for adding a campaign_id
to every response:
// Can be in a seperate d.ts file
module 'patreon-api.ts' {
interface ResponseTransformMap<Query extends BasePatreonQuery> {
custom: (response: GetResponsePayload<Query>) => {
response: GetResponsePayload<Query>
campaign_id: string
}
}
}
import {
type BasePatreonQuery,
type GetResponsePayload,
PatreonCreatorClient,
QueryBuilder,
} from 'patreon-api.ts'
// Replace this with your client
declare const client: PatreonCreatorClient
// Use the same key as in the module augmentation above
const parser = PatreonCreatorClient.createCustomParser(client, 'custom', false, (res) => ({
response: res,
campaign_id: '123',
}))
const query = QueryBuilder.campaigns.addRelationships(['creator']).setAttributes({
campaign: ['patron_count']
})
parser.fetchCampaigns(query)
.then(payload => payload.response.data[0].relationships.creator.data.id)