Typeform2 1.0.1
dotnet add package Typeform2 --version 1.0.1
NuGet\Install-Package Typeform2 -Version 1.0.1
<PackageReference Include="Typeform2" Version="1.0.1" />
paket add Typeform2 --version 1.0.1
#r "nuget: Typeform2, 1.0.1"
// 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
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
- Create a basic API client
- Support for passing in an access token
- Nuget package flow
- Github CI for tests / build / publish
- Target .NET Standard / maximize compatibility
- Support for Responses API
- Support for Webhooks API
- Support for Create API
- Support OAuth flow to obtain access token
Product | Versions 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. |
-
.NETStandard 2.0
- Macross.Json.Extensions (>= 2.2.0)
- Refit (>= 6.1.15)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.