/typewriter

A compiler for generating strongly typed analytics clients from a tracking spec

Primary LanguageJavaScriptMIT LicenseMIT



Typewriter logo



CircleCI Status NPM Version License


Typewriter GIF Example

Install

$ yarn add -D typewriter

Validation Warnings

Language Build-Time Run-Time
JavaScript ❌ Types
❌ Naming
❌ Required Properties
✅ Intellisense
✅ Types
✅ Naming
✅ Required Properties
N/A
TypeScript ✅ Types
✅ Naming
✅ Required Properties
✅ Intellisense
✅ Types
✅ Naming
✅ Required Properties
N/A
Android (Java) ✅ Types
✅ Naming
❌ Required Properties
✅ Intellisense
✅ Types
✅ Naming
✅ Required Properties
N/A
iOS (Objective C) ✅ Types
✅ Naming
❌ Required Properties
✅ Intellisense
✅ Types
✅ Naming
✅ Required Properties
N/A

JSON Schema Setup

Using Segment Protocols? You can download a JSON Schema version of your Tracking Plan directly from the Segment Platform API. See the instructions below.

Typewriter supports generating clients from multiple events without collisions, where each event is validated by its own JSON Schema. A minimal example might look like:

{
  "events": [
    {
      "name": "Viewed Typewriter",
      "description": "Fired when a user views the Typewriter landing page",
      "rules": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "type": "object",
        "properties": {
          "properties": {
            "type": "object",
            "properties": {
              "user_id": {
                "type": "string",
                "description": "The user viewing Typewriter"
              }
            }
          }
        },
        "required": ["properties"]
      }
    }
  ]
}

Typewriter supports JSON Schema draft-04 through draft-07.

Quickstarts

JavaScript / TypeScript Quickstart

First, generate a Typewriter client from your schema:

$ typewriter gen-js \
  --inputPath ./schema.json \
  --outputPath ./generated \
  --declarations ts

By default, the JavaScript client is generated as ES6. To customize the language target (and module format), use the --target and --module flags (run typewriter gen-js --help to see all available module formats and target syntaxes)

Then, import analytics.js and the generated Typewriter client to start making type-safe calls!

import TypewriterAnalytics from './generated'

// Pass in your analytics.js instance to Typewriter
const analytics = new TypewriterAnalytics(analyticsJS)

analytics.viewedTypewriter({
  profile_id: '1234'
})

To see a full working example, see the JavaScript example here or the TypeScript example here.

We recommend that you add client generation as a package.json command:

// package.json
{
  "scripts": {
    "typewriter": "typewriter gen-js --inputPath ./schema.json --outputPath ./generated"
  }
}

Node.js Quickstart

First, generate a Typewriter client from your schema:

$ typewriter gen-js \
  --inputPath ./schema.json \
  --outputPath ./generated \
  --client node \
  --target "ES2017" \
  --module "CommonJS" \
  --declarations ts

Then, import analytics-node and the generated Typewriter client to start making type-safe calls!

const TypewriterAnalytics = require('./generated')

// Pass in your analytics-node instance to Typewriter
const analytics = new TypewriterAnalytics(analyticsNode)

analytics.viewedTypewriter({
  properties: {
    user_id: '1234'
  }
})

To see a full working example, see the Node.js example here.

We recommend that you add client generation as a package.json command.

Android Quickstart

First, generate a Typewriter client from your schema:

$ typewriter gen-android \
  --inputPath ./schema.json \
  --outputPath ./generated \
  --language "java"

Then, configure a new analytics-android instance:

import com.segment.analytics.Analytics;
// Your generated Typewriter client
import com.segment.analytics.KicksAppAnalytics;

// ...

Analytics analytics = new Analytics.Builder(this, SEGMENT_WRITE_KEY)
        .trackApplicationLifecycleEvents()
        .recordScreenViews()
        .build();
this.kicksAppAnalytics = new KicksAppAnalytics(analytics);

Finally, start making type-safe calls!

OrderCompleted order = new OrderCompleted.Builder()
        .currency("USD")
        .orderID(UUID.randomUUID().toString())
        .total(13.37)
        .build();

this.kicksAppAnalytics.orderCompleted(order);

To see a full working example, see the Android Java example here.

iOS Quickstart

First, generate a Typewriter client from your schema:

$ typewriter gen-ios \
  --inputPath ./schema.json \
  --outputPath ./generated \
  --language "objectivec"

Then, configure a new analytics-ios instance:

#import <Analytics/SEGAnalytics.h>
// Your generated Typewriter client
#import "Analytics/SEGKicksAppAnalytics.h"

// ...

self.kicksAppAnalytics = [[SEGKicksAppAnalytics alloc] initWithAnalytics:[SEGAnalytics sharedAnalytics]];

Finally, start making type-safe calls!

SEGOrderCompleted *order = [SEGOrderCompletedBuilder initWithBlock:^(SEGOrderCompletedBuilder *builder) {
    builder.currency = @"USD";
    builder.orderID = [[NSUUID UUID] UUIDString];
    builder.total = productPrice;
}];
[self.kicksAppAnalytics orderCompleted:order];

To see a full working example, see the iOS Objective C example here.

Protocols Customers

If you use Segment Protocols, you can automatically generate clients from your Tracking Plan for any supported language.

To do so, you'll need your workspace slug and Tracking Plan id. You can find both in the URL when viewing your Tracking Plan: https://app.segment.com/<WORKSPACE_SLUG>/protocols/tracking-plans/<TRACKING_PLAN_ID>

  1. First, you'll want to generate a personal API token:
$ USER=me@example.com
$ PASS=foobar
$ WORKSPACE_SLUG=your_slug

$ curl \
  -d "{'access_token': {'description': 'Typewriter Personal Access Token', 'scopes': 'workspace:read', 'workspaceNames': [ 'workspaces/${WORKSPACE_SLUG}' ] }}" \
  -u "$USER:$PASS" \
  https://platform.segmentapis.com/v1beta/access-tokens
  1. Then, you can download a Tracking Plan with the sync command:
$ TRACKING_PLAN_ID=rs_foobar
$ PERSONAL_ACCESS_TOKEN=1234.4321
$ WORKSPACE_SLUG=your_slug

$ typewriter sync \
  --trackingPlanId ${TRACKING_PLAN_ID} \
  --token ${PERSONAL_ACCESS_TOKEN} \
  --workspaceSlug ${WORKSPACE_SLUG} \
  --outputPath ./generated/tracking-plan.json
  1. Great! You're now setup to follow any of the quickstarts above!

Contributing