0

Create Document from Template

by
Published today

Copy a template Doc and fill its {{placeholders}}. Requires the drive scope on the connection, in addition to documents.

Script gdocs Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 5 hours ago
1
//native
2

3
/**
4
 * Create Document from Template
5
 * Copy a template Google Doc and replace each `{{key}}` placeholder (in every tab) with the matching value from `variables`, e.g. `{"name": "Ada"}` fills `{{name}}`. Placeholders are matched case-sensitively; unmatched ones are left as-is. Requires the drive scope on the connection (to copy a template the app didn't create), in addition to documents.
6
 */
7
export async function main(
8
  auth: RT.Gdocs,
9
  template_id: string,
10
  title: string,
11
  variables: { [key: string]: any },
12
  folder_id: string | undefined
13
) {
14
  const copy = await fetch(
15
    `https://www.googleapis.com/drive/v3/files/${template_id}/copy?supportsAllDrives=true`,
16
    {
17
      method: "POST",
18
      headers: {
19
        Authorization: `Bearer ${auth.token}`,
20
        "Content-Type": "application/json",
21
        Accept: "application/json",
22
      },
23
      body: JSON.stringify({
24
        name: title,
25
        parents: folder_id ? [folder_id] : undefined,
26
      }),
27
    }
28
  )
29
  if (!copy.ok) {
30
    throw new Error(`${copy.status} ${await copy.text()}`)
31
  }
32
  const { id: document_id } = (await copy.json()) as { id: string }
33

34
  const requests = Object.entries(variables ?? {}).map(([key, value]) => ({
35
    replaceAllText: {
36
      containsText: { text: `{{${key}}}`, matchCase: true },
37
      replaceText: String(value ?? ""),
38
    },
39
  }))
40
  let replies: any[] = []
41
  if (requests.length) {
42
    const response = await fetch(
43
      `https://docs.googleapis.com/v1/documents/${document_id}:batchUpdate`,
44
      {
45
        method: "POST",
46
        headers: {
47
          Authorization: `Bearer ${auth.token}`,
48
          "Content-Type": "application/json",
49
          Accept: "application/json",
50
        },
51
        body: JSON.stringify({ requests }),
52
      }
53
    )
54
    if (!response.ok) {
55
      throw new Error(`${response.status} ${await response.text()}`)
56
    }
57
    replies = (await response.json()).replies ?? []
58
  }
59

60
  return {
61
    document_id,
62
    title,
63
    url: `https://docs.google.com/document/d/${document_id}/edit`,
64
    occurrences_changed: Object.fromEntries(
65
      Object.keys(variables ?? {}).map((k, i) => [
66
        k,
67
        replies[i]?.replaceAllText?.occurrencesChanged ?? 0,
68
      ])
69
    ),
70
  }
71
}
72