Typeform2 1.0.1

dotnet add package Typeform2 --version 1.0.1
NuGet\Install-Package Typeform2 -Version 1.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Typeform2" Version="1.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Typeform2 --version 1.0.1
#r "nuget: Typeform2, 1.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Typeform2 as a Cake Addin
#addin nuget:?package=Typeform2&version=1.0.1

// Install Typeform2 as a Cake Tool
#tool nuget:?package=Typeform2&version=1.0.1

typeform-dotnet

.NET Nuget Nuget

A .NET Standard 2.0 SDK wrapper built with Refit around Typeform's API.

Supported Endpoints

Install

via Nuget

# Package Manager
Install-Package Typeform2

# dotnet
dotnet add package Typeform2

Usage

Create API client

To create an instance of the Refit ITypeformApi client:

using Typeform;

var client = TypeformClient.CreateApi();

.NET Service Injection

using Typeform;

// TODO: Not Implemented Yet
// services.AddTypeformApi();

// You can always do this
services.AddRefitClient<ITypeformApi>(TypeformClient.DefaultSettings);

Other DI Containers

using Typeform;

// Ninject
kernel.Bind<ITypeformApi>().ToMethod(ctx => TypeformClient.CreateApi()).InSingletonScope();

Customizing Refit Settings

TypeformClient.DefaultSettings contains the default Refit settings used for the API. You can create new derived settings to pass if you need to through the CreateApi static method.

TypeformClient.DefaultSystemTextJsonSerializerOptions contains the default System.Text.Json serializer options. This handles naming policy and JSON deserialization according to the requirements of the Typeform API.

Consuming the API

You will need to pass your Typeform OAuth or Personal Access Token. Currently, this is implemented as a string argument to the endpoint methods.

TODO: Obtaining an OAuth token is not implemented yet. But for server-side flows, usually a Personal Access Token is "good enough."

public class HomeController : Controller {
  private readonly IConfiguration _configuration;
  private readonly ITypeformApi _typeformApi;

  public Controller(IConfiguration configuration, ITypeformApi typeformApi) {
    _configuration = configuration;
    _typeformApi = typeformApi;
  }

  public async Task<ActionResult> Index() {
    var accessToken = _configuration["TypeformAccessToken"]
    var formId = "abc123";

    var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);
  }
}

Responses API

Retrieve Responses

The Typeform Responses API returns form responses that include answers. Each answer can be a different type and to accomodate this, the SDK deserializes into different class implementations based on the answer type discriminator.

Retrieving an answer by type

If you know what type an answer is supposed to be, you can use the Answers.GetAnswer<T>(index) method to retrieve an answer at an index that is the expected type:

Answer By Index

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's answer as Text type (by index)
var answerText = responses.Items[0].Answers.GetAnswer<TypeformAnswerText>(0);

Answer By Field ID

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's answer as Text type (by field.id)
var answerText = responses.Items[0].Answers.GetAnswerById<TypeformAnswerText>("abc123");

Answer By Field Ref

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's answer as Text type (by field.ref)
var answerText = responses.Items[0].Answers.GetAnswerByRef<TypeformAnswerText>("my_custom_ref");

If you do not know what type an answer is supposed to be, you can inspect its type:

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's answer type
var firstAnswerType = responses.Items[0].Answers[0].Type;

if (firstAnswerType == TypeformAnswerType.Text) {
  var firstAnswer = responses.Items[0].Answers[0] as TypeformAnswerText;
}

Based on Typeform's response structure, it's not easily possible to get static typing of the answers without knowing the type in advance.

Answer type mapping

For reference, this is the mapping for each answer type used:

// Get the answer type enum value
var type = answer.Type;

// Determine the class type to map to
Type answerInstanceType = type switch
{
  TypeformAnswerType.Boolean => typeof(TypeformAnswerBoolean),
  TypeformAnswerType.Choice => typeof(TypeformAnswerChoice),
  TypeformAnswerType.Choices => typeof(TypeformAnswerChoices),
  TypeformAnswerType.Date => typeof(TypeformAnswerDate),
  TypeformAnswerType.Email => typeof(TypeformAnswerEmail),
  TypeformAnswerType.FileUrl => typeof(TypeformAnswerFileUrl),
  TypeformAnswerType.Number => typeof(TypeformAnswerNumber),
  TypeformAnswerType.Payment => typeof(TypeformAnswerPayment),
  TypeformAnswerType.PhoneNumber => typeof(TypeformAnswerPhoneNumber),
  TypeformAnswerType.Text => typeof(TypeformAnswerText),
  TypeformAnswerType.Url => typeof(TypeformAnswerUrl),
  _ => typeof(TypeformAnswer)
};

The SDK deserialization takes care of deserializing to the correct type so you can safely cast it.

Retrieving a variable's type

A form variables collection is similar to answers. You can use the same pattern to get variables by type.

Variables By Index

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's variable (by index)
var answerText = responses.Items[0].Variables.GetVariable<TypeformVariableText>(0);

Variables By Key

var responses = await _typeformApi.GetFormResponsesAsync(accessToken, formId);

// Retrieve first response's variable (by key)
var answerText = responses.Items[0].Variables.GetVariable<TypeformVariableText>("name");

Delete Responses

Use ITypeformApi.DeleteResponsesAsync() and pass a list of response IDs to delete.

Retrieve Response File

Uploaded files to a form can be downloaded via the REST API.

Retrieve file by file_url

The Typeform docs specify that you cannot rely on the values of file_url in Form Responses to have a consistent structure.

However, I have found that many file_url values do match the REST endpoint path value. To accommodate this, I've added an extension method GetFormResponseFileStreamFromUrlAsync which you can use to pass a FileUrl value directly and attempt to download a file.

ITypeformApi typeformApi = TypeformClient.CreateApi();

var responses = await typeformApi.GetFormResponsesAsync(accessToken, formId);
var uploadFileAnswer = responses.Items[0].Answers.GetAnswerByRef<TypeformAnswerFileUrl>("my_custom_upload_ref");

ApiResponse<Stream> fileResponse = await typeformApi.GetFormResponseFileStreamFromUrlAsync(
  accessToken,
  uploadFileAnswer.FileUrl
);

var contents = await fileResponse.ReadAllBytesAsync(/* chunkSize: <optional value in bytes> */);

await System.IO.File.WriteAllBytesAsync(filename, contents);

Retrieve file by parameters

You can also manually specify the form_id, response_id, field_id and filename to download using ITypeformApi.GetFormResponseFileStreamAsync().

The return value of this method is a Refit ApiResponse<Stream> and you can manipulate the Stream response any way you see fit. There is a ReadAllBytesAsync() extension method that will read the full bytes using a chunked buffer:

ITypeformApi typeformApi = TypeformClient.CreateApi();

ApiResponse<Stream> fileResponse = await typeformApi.GetFormResponseFileStreamAsync(
  accessToken,
  formId,
  responseId,
  fieldId,
  filename
);

var contents = await fileResponse.ReadAllBytesAsync(/* chunkSize: <optional value in bytes> */);

await System.IO.File.WriteAllBytesAsync(filename, contents);

If you need to download a file using a FileUrl value from the Form Responses API, you will need to construct your own HttpClient to download it like this example.

TODO

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.1 90 9/28/2023
1.0.0 712 9/25/2023