Building a friendly .NET SDK to connect to Space

Maarten Balliauw
Maarten BalliauwDeveloper Advocate
Building a friendly .NET SDK to
connect to Space
Maarten Balliauw
@maartenballiauw
Agenda
JetBrains Space
JetBrains Space HTTP API
Building a .NET SDK for the Space HTTP API
Code generation
Developer experience
JetBrains Space
JetBrains Space
Integrated Team Environment
https://jetbrains.space
People
Teams
Projects
-
Workspaces
for teams
Collaboration
JetBrains Space
demo
The Space HTTP API
Integrated Team Environment
More information in Space == more value from Space
Internal integrations out of the box
Vacation shown in profile
Blog post targeted to team/location
Calendar integration in blog post
Everything can be a ToDo item
...
What with external integrations? Extensibility?
Everything as an HTTP API!
What do you want to build? Which integration do you need?
Import data
Post to chat
Manage users, teams, and locations programatically
Build dashboards
No good answer, so opening up everything
Large HTTP API surface...
HTTP API Playground to explore!
HTTP API Playground
demo
$fields
Top-level fields returned by default
Unless $fields query parameter used
Use $fields to be specific, or get nested fields
$fields=id,icon,name
$fields=id,name,boards(id,description)
$fields=id,name,boards(id,info(columns))
$fields=*,boards(id,description)
Building a .NET SDK
for the Space HTTP API
Hello, .NET! 👋
Goal: make our users succesful at using Space in their team/organization
Provide a ready-to-use SDK
Minimal configuration needed
Discoverability
TL;DR: Lead integration developers on the shortest path to success
How? Handcrafted
No.
Over 150 API endpoints
Over 700 object types
Space EAP / Space Beta means churn!
How? OpenAPI?
Use NSwag, generate based on OpenAPI / Swagger document
Some incompatible object types needed custom code generation
How? OpenAPI?
Not very developer friendly...
public class Body
{
public string Member { get; set; }
public string Reason { get; set; }
public string Description { get; set; }
public string Location { get; set; }
public string Since { get; set; }
public string Till { get; set; }
public bool Available { get; set; } = false;
public string Icon { get; set; }
}
public async Task<AbsenceRecord> GetAbsencesAsync(
string fields, Body body, CancellationToken cancellationToken)
{
}
How? Custom code generation
Space exposes HTTP API Model
Enumerations
DTOs (objects passed around)
Resources
+ data types, nullability,
default values, ...
https://your.jetbrains.space/api/http/http-api-model?$fields=dto,enums,urlParams,resources(*,nestedResources!)
Enumeration model
public class ApiEnum
{
public string Id { get; set; }
public ApiDeprecation? Deprecation { get; set; }
public string Name { get; set; }
public List<string> Values { get; set; }
}
public class ApiDeprecation
{
public string? Message { get; set; }
public string? Since { get; set; }
public bool ForRemoval { get; set; }
}
Enumeration code generator
public class EnumerationVisitor
{
public string Visit(ApiEnum apiEnum)
{
var builder = new StringBuilder();
if (apiEnum.Deprecation != null)
builder.AppendLine(Visit(apiEnum.Deprecation));
builder.AppendLine("public enum " + apiEnum.Name);
builder.AppendLine("{");
foreach (var apiEnumValue in apiEnum.Values)
{
builder.AppendLine($" {apiEnumValue},");
}
builder.AppendLine("}");
return builder.ToString();
}
public string Visit(ApiDeprecation apiDeprecation)
=> $"[Obsolete("{apiDeprecation.Message}")]";
}
public enum AbsenceListMode
{
All,
WithAccessibleReasonUnapproved,
WithAccessibleReasonAll,
}
DTO model
public class ApiDto
{
public string Id { get; set; }
public ApiDeprecation? Deprecation { get; set; }
public string Name { get; set; } = default!;
public List<ApiDtoField> Fields { get; set; }
public Reference<ApiDto>? Extends { get; set; }
public List<Reference<ApiDto>> Implements { get; set; }
public List<Reference<ApiDto>> Inheritors { get; set; }
public HierarchyRole HierarchyRole { get; set; }
public bool Record { get; set; }
}
public class ApiField
{
public string Name { get; set; }
public ApiFieldType Type { get; set; }
public bool Optional { get; set; }
public ApiDefaultValue? DefaultValue { get; set; }
}
Endpoints model
Endpoint id, name, base path
Resource id, name, path, parameters
Resource id, name, path, parameters
Resource id, name, path, parameters
...
+ parameter types
+ return types
+ default values (const, variable)
Custom code generation
demo
Roslyn/StringBuilder/...?
Generally, a few ways to generate code:
IL-based
IL Generation (Reflection.Emit)
Model-based
CodeDOM
Expression trees
Roslyn syntax generation
Template-based (T4, Razor, ...)
Strings all the way
https://amzn.to/2EWsA44
Strings all the way!
See string, recognize the output easily
IL-based – Too complex
Model-based – Less readable (very verbose)
Template-based – Less readable (many small files to include)
builder.AppendLine(
$"public {subject.Type.ToCSharpType()} {subject.ToCSharpPropertyName()} {{ get; set; }}");
var propertyDeclaration = SyntaxFactory.PropertyDeclaration(
SyntaxFactory.ParseTypeName(subject.Type.ToCSharpType()), subject.ToCSharpPropertyName())
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
Extension methods everywhere
Many places where we need:
C# class name
C# variable name
C# type from Space model type
...
public static class ApiDocumentationExtensions
{
public static string ToCSharpDocumentationComment(
this string subject)
{
var builder = new StringBuilder();
builder.AppendLine("/// <summary>");
builder.AppendLine("/// " + subject);
builder.AppendLine("/// </summary>");
return builder.ToString();
}
}
public static class ApiDtoExtensions
{
public static string ToCSharpClassName(this ApiDto subject)
=> CSharpIdentifier.ForClassOrNamespace(subject.Name);
}
System.Text.Json
“System.Text.Json is a built-in (de)serializer for .NET Core 3 and beyond.”
Developer experience!
No extra dependencies needed
No dependency on a Newtonsoft.Json that you are not using
System.Text.Json
Not a 100% replacement for Newtonsoft.Json...
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-
from-newtonsoft-how-to
System.Text.Json is extensible enough
Custom JsonConverter<T>
JsonConverter<T>
demo
https://blog.maartenballiauw.be/post/2020/01/29/deserializing-
json-into-polymorphic-classes-with-systemtextjson.html
Code generation & developer
experience
The ideal “Getting started”
1. Register application in Space
2. Install SpaceDotNet.Client package
dotnet add package SpaceDotNet.Client
3. Create connection instance
var connection = new ClientCredentialsConnection(
"https://your.jetbrains.space/",
"client-id",
"client-secret",
new HttpClient());
4. Profit!
Large API surface
var teamDirectoryClient = new TeamDirectoryClient(connection);
var birthdays = await teamDirectoryClient
.CalendarEvents
.BirthdayEvents
.GetAllBirthdayEventsAsync(...);
Remember $fields ?
Top-level fields returned by default
Unless $fields query parameter used
Use $fields to be specific, or get nested fields
$fields
Top-level fields returned by default
Use partial to be specific, or get nested fields
var memberProfile = await teamDirectoryClient.Profiles
.GetProfileAsync(ProfileIdentifier.Username("Heather.Stewart"));
var memberProfile = await teamDirectoryClient.Profiles
.GetProfileAsync(ProfileIdentifier.Username("Heather.Stewart"), _ => _
.WithAllFieldsWildcard() // with all top level fields
.WithManagers(managers => managers // include managers
.WithId() // with their Id
.WithUsername() // and their Username
.WithName(name => name // and their Name
.WithFirstName() // with FirstName
.WithLastName()))); // and LastName
Developer experience
demo
Batches (e.g. Get all ToDo items)
public class Batch<T>
{
List<T>? Data { get; }
string? Next { get; }
int? TotalCount { get; }
bool HasNext();
}
var batch = await _todoClient.GetAllToDoItemsAsync(
from: weekStart.AsSpaceDate(),
partial: _ => _
.WithData(data => data
// ...
.WithTotalCount()
.WithNext());
do
{
foreach (var todo in batch.Data)
{
// ...
}
batch = await _todoClient.GetAllToDoItemsAsync(
from: weekStart.AsSpaceDate(),
skip: batch.Next,
partial: _ => _ /* ... */);
}
while (batch.HasNext());
await foreach (var todo in _todoClient
.GetAllToDoItemsAsyncEnumerable(from: weekStart.AsSpaceDate(), partial: _ => _
.WithId()
.WithContent(content => content
.ForInherited<TodoItemContentMdText>(md => md
.WithAllFieldsWildcard()))
.WithStatus()))
{
// ...
}
IAsyncEnumerable to the rescue!
⚠ Don’t use it for .Count()
var batch = await _todoClient.GetAllToDoItemsAsync(
from: weekStart.AsSpaceDate(), partial: _ => _.WithTotalCount());
var numberOfResults = batch.TotalCount;
Batches and
IAsyncEnumerable
demo
Request bodies are flattened
GetAbsences(AbsencesRequest request)
GetAbsences(string member, string reason, ...)
Factory methods for inheritors
Which option would you prefer?
await chatClient.Messages.SendMessageAsync(
recipient: new MessageRecipientChannel()
{
Channel = new ChatChannelFromName()
{
Name = chatChannelName
}
},
await chatClient.Messages.SendMessageAsync(
recipient: MessageRecipient.Channel(ChatChannel.FromName(chatChannelName)),
Default values
Unfortunatey not possible in C#...
Workaround:
Unfortunately not obvious what the default is when not specified.
Should we add XMLdoc instead?
public async IAsyncEnumerable<AbsenceRecord> GetAllAbsencesAsyncEnumerable(
AbsenceListMode viewMode = AbsenceListMode.All, string? member = null)
public IAsyncEnumerable<AbsenceRecord> GetAllAbsencesAsyncEnumerable(
AbsenceListMode? viewMode = null, string? member = null)
=> BatchEnumerator.AllItems(
() => GetAllAbsencesAsync(viewMode: viewMode ?? AbsenceListMode.All, member: member);
Code generation
demo
Developer experience (extras)
Use SpaceDotNet in web apps
public void ConfigureServices(IServiceCollection services)
{
// ...
// Space authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = SpaceDefaults.AuthenticationScheme;
})
.AddCookie()
.AddSpace(options => Configuration.Bind("Space", options))
.AddSpaceTokenManagement(); // auto-refreshes tokens in the background and provides a Space connection
// Space client API
services.AddSpaceClientApi();
// Space webhook receiver
services.AddSpaceWebHookHandler<CateringWebHookHandler>(options => Configuration.Bind("Space", options));
Use SpaceDotNet in web apps
.AddSpace()
Use Space for authN
.AddSpaceClientApi()
Register ...Client with service collection
.AddSpaceTokenManagement() (experimental)
Auto-refreshes tokens in the background
Space client always auth’ed as currently logged in user
.AddSpaceWebHookHandler<T>() (experimental)
Webhook support
Use SpaceDotNet
in web apps
demo
Conclusion
Conclusion
JetBrains Space is an Integrated Team Environment
JetBrains Space HTTP API exposes everything
Building a .NET SDK for the Space HTTP API
Goal: make our users succesful at using Space
Provide a ready-to-use SDK
Minimal configuration needed
Discoverability
Code generation
Focus on developer experience
Thank you!
https://blog.maartenballiauw.be
@maartenballiauw
1 of 47

Recommended

Natural Language Query and Conversational Interface to Apache Spark by
Natural Language Query and Conversational Interface to Apache SparkNatural Language Query and Conversational Interface to Apache Spark
Natural Language Query and Conversational Interface to Apache SparkDatabricks
218 views29 slides
02 integrate highchart by
02 integrate highchart02 integrate highchart
02 integrate highchartErhwen Kuo
2.5K views54 slides
05 integrate redis by
05 integrate redis05 integrate redis
05 integrate redisErhwen Kuo
3.1K views57 slides
Degrading Performance? You Might be Suffering From the Small Files Syndrome by
Degrading Performance? You Might be Suffering From the Small Files SyndromeDegrading Performance? You Might be Suffering From the Small Files Syndrome
Degrading Performance? You Might be Suffering From the Small Files SyndromeDatabricks
421 views22 slides
MLflow Model Serving by
MLflow Model ServingMLflow Model Serving
MLflow Model ServingDatabricks
1.4K views51 slides
Spark and S3 with Ryan Blue by
Spark and S3 with Ryan BlueSpark and S3 with Ryan Blue
Spark and S3 with Ryan BlueDatabricks
3.9K views29 slides

More Related Content

What's hot

Building a Data Pipeline from Scratch - Joe Crobak by
Building a Data Pipeline from Scratch - Joe CrobakBuilding a Data Pipeline from Scratch - Joe Crobak
Building a Data Pipeline from Scratch - Joe CrobakHakka Labs
38.6K views55 slides
Apache Zeppelin Meetup Christian Tzolov 1/21/16 by
Apache Zeppelin Meetup Christian Tzolov 1/21/16 Apache Zeppelin Meetup Christian Tzolov 1/21/16
Apache Zeppelin Meetup Christian Tzolov 1/21/16 PivotalOpenSourceHub
745 views25 slides
Building Data Pipelines in Python by
Building Data Pipelines in PythonBuilding Data Pipelines in Python
Building Data Pipelines in PythonC4Media
11.8K views52 slides
Overview of the Hive Stinger Initiative by
Overview of the Hive Stinger InitiativeOverview of the Hive Stinger Initiative
Overview of the Hive Stinger InitiativeModern Data Stack France
1.4K views18 slides
Hazelcast by
HazelcastHazelcast
HazelcastJeevesh Pandey
1.1K views49 slides
Building cloud-enabled genomics workflows with Luigi and Docker by
Building cloud-enabled genomics workflows with Luigi and DockerBuilding cloud-enabled genomics workflows with Luigi and Docker
Building cloud-enabled genomics workflows with Luigi and DockerJacob Feala
5.9K views55 slides

What's hot(20)

Building a Data Pipeline from Scratch - Joe Crobak by Hakka Labs
Building a Data Pipeline from Scratch - Joe CrobakBuilding a Data Pipeline from Scratch - Joe Crobak
Building a Data Pipeline from Scratch - Joe Crobak
Hakka Labs38.6K views
Building Data Pipelines in Python by C4Media
Building Data Pipelines in PythonBuilding Data Pipelines in Python
Building Data Pipelines in Python
C4Media11.8K views
Building cloud-enabled genomics workflows with Luigi and Docker by Jacob Feala
Building cloud-enabled genomics workflows with Luigi and DockerBuilding cloud-enabled genomics workflows with Luigi and Docker
Building cloud-enabled genomics workflows with Luigi and Docker
Jacob Feala5.9K views
Building a Large Scale SEO/SEM Application with Apache Solr by Rahul Jain
Building a Large Scale SEO/SEM Application with Apache SolrBuilding a Large Scale SEO/SEM Application with Apache Solr
Building a Large Scale SEO/SEM Application with Apache Solr
Rahul Jain1.7K views
04 integrate entityframework by Erhwen Kuo
04 integrate entityframework04 integrate entityframework
04 integrate entityframework
Erhwen Kuo653 views
Speed up Interactive Analytic Queries over Existing Big Data on Hadoop with P... by viirya
Speed up Interactive Analytic Queries over Existing Big Data on Hadoop with P...Speed up Interactive Analytic Queries over Existing Big Data on Hadoop with P...
Speed up Interactive Analytic Queries over Existing Big Data on Hadoop with P...
viirya3.1K views
Building a unified data pipeline in Apache Spark by DataWorks Summit
Building a unified data pipeline in Apache SparkBuilding a unified data pipeline in Apache Spark
Building a unified data pipeline in Apache Spark
DataWorks Summit26.2K views
03 integrate webapisignalr by Erhwen Kuo
03 integrate webapisignalr03 integrate webapisignalr
03 integrate webapisignalr
Erhwen Kuo553 views
Getting started with Apollo Client and GraphQL by Morgan Dedmon
Getting started with Apollo Client and GraphQLGetting started with Apollo Client and GraphQL
Getting started with Apollo Client and GraphQL
Morgan Dedmon1.5K views
Presto: Distributed SQL on Anything - Strata Hadoop 2017 San Jose, CA by kbajda
Presto: Distributed SQL on Anything -  Strata Hadoop 2017 San Jose, CAPresto: Distributed SQL on Anything -  Strata Hadoop 2017 San Jose, CA
Presto: Distributed SQL on Anything - Strata Hadoop 2017 San Jose, CA
kbajda1.6K views
Opaque: A Data Analytics Platform with Strong Security: Spark Summit East tal... by Spark Summit
Opaque: A Data Analytics Platform with Strong Security: Spark Summit East tal...Opaque: A Data Analytics Platform with Strong Security: Spark Summit East tal...
Opaque: A Data Analytics Platform with Strong Security: Spark Summit East tal...
Spark Summit1.5K views
Metadata based statistics for DSpace by Bram Luyten
Metadata based statistics for DSpaceMetadata based statistics for DSpace
Metadata based statistics for DSpace
Bram Luyten2.9K views
Case study of Rujhaan.com (A social news app ) by Rahul Jain
Case study of Rujhaan.com (A social news app )Case study of Rujhaan.com (A social news app )
Case study of Rujhaan.com (A social news app )
Rahul Jain2.4K views
NigthClazz Spark - Machine Learning / Introduction à Spark et Zeppelin by Zenika
NigthClazz Spark - Machine Learning / Introduction à Spark et ZeppelinNigthClazz Spark - Machine Learning / Introduction à Spark et Zeppelin
NigthClazz Spark - Machine Learning / Introduction à Spark et Zeppelin
Zenika1.1K views

Similar to Building a friendly .NET SDK to connect to Space

Architecture | Busy Java Developers Guide to NoSQL | Ted Neward by
Architecture | Busy Java Developers Guide to NoSQL | Ted NewardArchitecture | Busy Java Developers Guide to NoSQL | Ted Neward
Architecture | Busy Java Developers Guide to NoSQL | Ted NewardJAX London
1.8K views43 slides
03 form-data by
03 form-data03 form-data
03 form-datasnopteck
403 views23 slides
Introduction To Groovy 2005 by
Introduction To Groovy 2005Introduction To Groovy 2005
Introduction To Groovy 2005Tugdual Grall
856 views32 slides
Groovy Introduction - JAX Germany - 2008 by
Groovy Introduction - JAX Germany - 2008Groovy Introduction - JAX Germany - 2008
Groovy Introduction - JAX Germany - 2008Guillaume Laforge
1K views48 slides
Clean Code by
Clean CodeClean Code
Clean CodeNascenia IT
1.3K views41 slides
68837.ppt by
68837.ppt68837.ppt
68837.pptBruceLee275640
3 views23 slides

Similar to Building a friendly .NET SDK to connect to Space(20)

Architecture | Busy Java Developers Guide to NoSQL | Ted Neward by JAX London
Architecture | Busy Java Developers Guide to NoSQL | Ted NewardArchitecture | Busy Java Developers Guide to NoSQL | Ted Neward
Architecture | Busy Java Developers Guide to NoSQL | Ted Neward
JAX London1.8K views
03 form-data by snopteck
03 form-data03 form-data
03 form-data
snopteck403 views
Introduction To Groovy 2005 by Tugdual Grall
Introduction To Groovy 2005Introduction To Groovy 2005
Introduction To Groovy 2005
Tugdual Grall856 views
Visual Studio 2010 and .NET 4.0 Overview by bwullems
Visual Studio 2010 and .NET 4.0 OverviewVisual Studio 2010 and .NET 4.0 Overview
Visual Studio 2010 and .NET 4.0 Overview
bwullems1.3K views
Micro-ORM Introduction - Don't overcomplicate by Kiev ALT.NET
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicate
Kiev ALT.NET4.5K views
Data access 2.0? Please welcome: Spring Data! by Oliver Gierke
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
Oliver Gierke2K views
Twitter Author Prediction from Tweets using Bayesian Network by Hendy Irawan
Twitter Author Prediction from Tweets using Bayesian NetworkTwitter Author Prediction from Tweets using Bayesian Network
Twitter Author Prediction from Tweets using Bayesian Network
Hendy Irawan1.1K views
Dart Power Tools by Matt Norris
Dart Power ToolsDart Power Tools
Dart Power Tools
Matt Norris1.7K views
Embedded Typesafe Domain Specific Languages for Java by Jevgeni Kabanov
Embedded Typesafe Domain Specific Languages for JavaEmbedded Typesafe Domain Specific Languages for Java
Embedded Typesafe Domain Specific Languages for Java
Jevgeni Kabanov1.4K views
All you need to know about JavaScript Functions by Oluwaleke Fakorede
All you need to know about JavaScript FunctionsAll you need to know about JavaScript Functions
All you need to know about JavaScript Functions
Oluwaleke Fakorede179 views
CouchDB on Android by Sven Haiges
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges5.4K views
Object Graph Mapping with Spring Data Neo4j 3 - Nicki Watt & Michael Hunger @... by Neo4j
Object Graph Mapping with Spring Data Neo4j 3 - Nicki Watt & Michael Hunger @...Object Graph Mapping with Spring Data Neo4j 3 - Nicki Watt & Michael Hunger @...
Object Graph Mapping with Spring Data Neo4j 3 - Nicki Watt & Michael Hunger @...
Neo4j6.1K views
Introduction-to-Csharp.ppt by Almamoon
Introduction-to-Csharp.pptIntroduction-to-Csharp.ppt
Introduction-to-Csharp.ppt
Almamoon1 view

More from Maarten Balliauw

Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s... by
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...Maarten Balliauw
360 views64 slides
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo... by
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...Maarten Balliauw
406 views52 slides
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday... by
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...Maarten Balliauw
180 views32 slides
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain... by
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...Maarten Balliauw
326 views53 slides
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m... by
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...Maarten Balliauw
280 views42 slides
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se... by
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se....NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se...
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se...Maarten Balliauw
290 views28 slides

More from Maarten Balliauw(20)

Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s... by Maarten Balliauw
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...
Maarten Balliauw360 views
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo... by Maarten Balliauw
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...
Maarten Balliauw406 views
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday... by Maarten Balliauw
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...
Maarten Balliauw180 views
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain... by Maarten Balliauw
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
Maarten Balliauw326 views
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m... by Maarten Balliauw
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...
Maarten Balliauw280 views
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se... by Maarten Balliauw
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se....NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se...
.NET Conf 2019 - Indexing and searching NuGet.org with Azure Functions and Se...
Maarten Balliauw290 views
CloudBurst 2019 - Indexing and searching NuGet.org with Azure Functions and S... by Maarten Balliauw
CloudBurst 2019 - Indexing and searching NuGet.org with Azure Functions and S...CloudBurst 2019 - Indexing and searching NuGet.org with Azure Functions and S...
CloudBurst 2019 - Indexing and searching NuGet.org with Azure Functions and S...
Maarten Balliauw564 views
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search by Maarten Balliauw
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and SearchNDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search
Maarten Balliauw958 views
Approaches for application request throttling - Cloud Developer Days Poland by Maarten Balliauw
Approaches for application request throttling - Cloud Developer Days PolandApproaches for application request throttling - Cloud Developer Days Poland
Approaches for application request throttling - Cloud Developer Days Poland
Maarten Balliauw1.1K views
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve... by Maarten Balliauw
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...
Maarten Balliauw1.1K views
Approaches for application request throttling - dotNetCologne by Maarten Balliauw
Approaches for application request throttling - dotNetCologneApproaches for application request throttling - dotNetCologne
Approaches for application request throttling - dotNetCologne
Maarten Balliauw246 views
CodeStock - Exploring .NET memory management - a trip down memory lane by Maarten Balliauw
CodeStock - Exploring .NET memory management - a trip down memory laneCodeStock - Exploring .NET memory management - a trip down memory lane
CodeStock - Exploring .NET memory management - a trip down memory lane
Maarten Balliauw1.9K views
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain... by Maarten Balliauw
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
Maarten Balliauw1.2K views
ConFoo Montreal - Approaches for application request throttling by Maarten Balliauw
ConFoo Montreal - Approaches for application request throttlingConFoo Montreal - Approaches for application request throttling
ConFoo Montreal - Approaches for application request throttling
Maarten Balliauw1.2K views
Microservices for building an IDE – The innards of JetBrains Rider - TechDays... by Maarten Balliauw
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Maarten Balliauw10.5K views
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory... by Maarten Balliauw
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...
Maarten Balliauw1.1K views
DotNetFest - Let’s refresh our memory! Memory management in .NET by Maarten Balliauw
DotNetFest - Let’s refresh our memory! Memory management in .NETDotNetFest - Let’s refresh our memory! Memory management in .NET
DotNetFest - Let’s refresh our memory! Memory management in .NET
Maarten Balliauw480 views
VISUG - Approaches for application request throttling by Maarten Balliauw
VISUG - Approaches for application request throttlingVISUG - Approaches for application request throttling
VISUG - Approaches for application request throttling
Maarten Balliauw817 views
What is going on - Application diagnostics on Azure - TechDays Finland by Maarten Balliauw
What is going on - Application diagnostics on Azure - TechDays FinlandWhat is going on - Application diagnostics on Azure - TechDays Finland
What is going on - Application diagnostics on Azure - TechDays Finland
Maarten Balliauw746 views
ConFoo - Exploring .NET’s memory management – a trip down memory lane by Maarten Balliauw
ConFoo - Exploring .NET’s memory management – a trip down memory laneConFoo - Exploring .NET’s memory management – a trip down memory lane
ConFoo - Exploring .NET’s memory management – a trip down memory lane
Maarten Balliauw523 views

Recently uploaded

Initiating and Advancing Your Strategic GIS Governance Strategy by
Initiating and Advancing Your Strategic GIS Governance StrategyInitiating and Advancing Your Strategic GIS Governance Strategy
Initiating and Advancing Your Strategic GIS Governance StrategySafe Software
176 views68 slides
Business Analyst Series 2023 - Week 4 Session 7 by
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7DianaGray10
139 views31 slides
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...James Anderson
160 views32 slides
Business Analyst Series 2023 - Week 4 Session 8 by
Business Analyst Series 2023 -  Week 4 Session 8Business Analyst Series 2023 -  Week 4 Session 8
Business Analyst Series 2023 - Week 4 Session 8DianaGray10
123 views13 slides
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates by
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesKeynote Talk: Open Source is Not Dead - Charles Schulz - Vates
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesShapeBlue
252 views15 slides
State of the Union - Rohit Yadav - Apache CloudStack by
State of the Union - Rohit Yadav - Apache CloudStackState of the Union - Rohit Yadav - Apache CloudStack
State of the Union - Rohit Yadav - Apache CloudStackShapeBlue
297 views53 slides

Recently uploaded(20)

Initiating and Advancing Your Strategic GIS Governance Strategy by Safe Software
Initiating and Advancing Your Strategic GIS Governance StrategyInitiating and Advancing Your Strategic GIS Governance Strategy
Initiating and Advancing Your Strategic GIS Governance Strategy
Safe Software176 views
Business Analyst Series 2023 - Week 4 Session 7 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray10139 views
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by James Anderson
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
James Anderson160 views
Business Analyst Series 2023 - Week 4 Session 8 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 8Business Analyst Series 2023 -  Week 4 Session 8
Business Analyst Series 2023 - Week 4 Session 8
DianaGray10123 views
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates by ShapeBlue
Keynote Talk: Open Source is Not Dead - Charles Schulz - VatesKeynote Talk: Open Source is Not Dead - Charles Schulz - Vates
Keynote Talk: Open Source is Not Dead - Charles Schulz - Vates
ShapeBlue252 views
State of the Union - Rohit Yadav - Apache CloudStack by ShapeBlue
State of the Union - Rohit Yadav - Apache CloudStackState of the Union - Rohit Yadav - Apache CloudStack
State of the Union - Rohit Yadav - Apache CloudStack
ShapeBlue297 views
Digital Personal Data Protection (DPDP) Practical Approach For CISOs by Priyanka Aash
Digital Personal Data Protection (DPDP) Practical Approach For CISOsDigital Personal Data Protection (DPDP) Practical Approach For CISOs
Digital Personal Data Protection (DPDP) Practical Approach For CISOs
Priyanka Aash158 views
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue by ShapeBlue
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlueElevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue
ShapeBlue222 views
DRBD Deep Dive - Philipp Reisner - LINBIT by ShapeBlue
DRBD Deep Dive - Philipp Reisner - LINBITDRBD Deep Dive - Philipp Reisner - LINBIT
DRBD Deep Dive - Philipp Reisner - LINBIT
ShapeBlue180 views
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti... by ShapeBlue
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...
DRaaS using Snapshot copy and destination selection (DRaaS) - Alexandre Matti...
ShapeBlue139 views
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue by ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlueCloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
ShapeBlue135 views
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue by ShapeBlue
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlueWhat’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue
What’s New in CloudStack 4.19 - Abhishek Kumar - ShapeBlue
ShapeBlue263 views
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue by ShapeBlue
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlueVNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue
VNF Integration and Support in CloudStack - Wei Zhou - ShapeBlue
ShapeBlue203 views
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda... by ShapeBlue
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
Hypervisor Agnostic DRS in CloudStack - Brief overview & demo - Vishesh Jinda...
ShapeBlue161 views
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue by ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlueCloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
CloudStack Object Storage - An Introduction - Vladimir Petrov - ShapeBlue
ShapeBlue138 views
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ... by ShapeBlue
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...
Import Export Virtual Machine for KVM Hypervisor - Ayush Pandey - University ...
ShapeBlue119 views

Building a friendly .NET SDK to connect to Space

  • 1. Building a friendly .NET SDK to connect to Space Maarten Balliauw @maartenballiauw
  • 2. Agenda JetBrains Space JetBrains Space HTTP API Building a .NET SDK for the Space HTTP API Code generation Developer experience
  • 4. JetBrains Space Integrated Team Environment https://jetbrains.space People Teams Projects - Workspaces for teams Collaboration
  • 7. Integrated Team Environment More information in Space == more value from Space Internal integrations out of the box Vacation shown in profile Blog post targeted to team/location Calendar integration in blog post Everything can be a ToDo item ... What with external integrations? Extensibility?
  • 8. Everything as an HTTP API! What do you want to build? Which integration do you need? Import data Post to chat Manage users, teams, and locations programatically Build dashboards No good answer, so opening up everything Large HTTP API surface... HTTP API Playground to explore!
  • 10. $fields Top-level fields returned by default Unless $fields query parameter used Use $fields to be specific, or get nested fields $fields=id,icon,name $fields=id,name,boards(id,description) $fields=id,name,boards(id,info(columns)) $fields=*,boards(id,description)
  • 11. Building a .NET SDK for the Space HTTP API
  • 12. Hello, .NET! 👋 Goal: make our users succesful at using Space in their team/organization Provide a ready-to-use SDK Minimal configuration needed Discoverability TL;DR: Lead integration developers on the shortest path to success
  • 13. How? Handcrafted No. Over 150 API endpoints Over 700 object types Space EAP / Space Beta means churn!
  • 14. How? OpenAPI? Use NSwag, generate based on OpenAPI / Swagger document Some incompatible object types needed custom code generation
  • 15. How? OpenAPI? Not very developer friendly... public class Body { public string Member { get; set; } public string Reason { get; set; } public string Description { get; set; } public string Location { get; set; } public string Since { get; set; } public string Till { get; set; } public bool Available { get; set; } = false; public string Icon { get; set; } } public async Task<AbsenceRecord> GetAbsencesAsync( string fields, Body body, CancellationToken cancellationToken) { }
  • 16. How? Custom code generation Space exposes HTTP API Model Enumerations DTOs (objects passed around) Resources + data types, nullability, default values, ... https://your.jetbrains.space/api/http/http-api-model?$fields=dto,enums,urlParams,resources(*,nestedResources!)
  • 17. Enumeration model public class ApiEnum { public string Id { get; set; } public ApiDeprecation? Deprecation { get; set; } public string Name { get; set; } public List<string> Values { get; set; } } public class ApiDeprecation { public string? Message { get; set; } public string? Since { get; set; } public bool ForRemoval { get; set; } }
  • 18. Enumeration code generator public class EnumerationVisitor { public string Visit(ApiEnum apiEnum) { var builder = new StringBuilder(); if (apiEnum.Deprecation != null) builder.AppendLine(Visit(apiEnum.Deprecation)); builder.AppendLine("public enum " + apiEnum.Name); builder.AppendLine("{"); foreach (var apiEnumValue in apiEnum.Values) { builder.AppendLine($" {apiEnumValue},"); } builder.AppendLine("}"); return builder.ToString(); } public string Visit(ApiDeprecation apiDeprecation) => $"[Obsolete("{apiDeprecation.Message}")]"; } public enum AbsenceListMode { All, WithAccessibleReasonUnapproved, WithAccessibleReasonAll, }
  • 19. DTO model public class ApiDto { public string Id { get; set; } public ApiDeprecation? Deprecation { get; set; } public string Name { get; set; } = default!; public List<ApiDtoField> Fields { get; set; } public Reference<ApiDto>? Extends { get; set; } public List<Reference<ApiDto>> Implements { get; set; } public List<Reference<ApiDto>> Inheritors { get; set; } public HierarchyRole HierarchyRole { get; set; } public bool Record { get; set; } } public class ApiField { public string Name { get; set; } public ApiFieldType Type { get; set; } public bool Optional { get; set; } public ApiDefaultValue? DefaultValue { get; set; } }
  • 20. Endpoints model Endpoint id, name, base path Resource id, name, path, parameters Resource id, name, path, parameters Resource id, name, path, parameters ... + parameter types + return types + default values (const, variable)
  • 22. Roslyn/StringBuilder/...? Generally, a few ways to generate code: IL-based IL Generation (Reflection.Emit) Model-based CodeDOM Expression trees Roslyn syntax generation Template-based (T4, Razor, ...) Strings all the way https://amzn.to/2EWsA44
  • 23. Strings all the way! See string, recognize the output easily IL-based – Too complex Model-based – Less readable (very verbose) Template-based – Less readable (many small files to include) builder.AppendLine( $"public {subject.Type.ToCSharpType()} {subject.ToCSharpPropertyName()} {{ get; set; }}"); var propertyDeclaration = SyntaxFactory.PropertyDeclaration( SyntaxFactory.ParseTypeName(subject.Type.ToCSharpType()), subject.ToCSharpPropertyName()) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddAccessorListAccessors( SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)), SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
  • 24. Extension methods everywhere Many places where we need: C# class name C# variable name C# type from Space model type ... public static class ApiDocumentationExtensions { public static string ToCSharpDocumentationComment( this string subject) { var builder = new StringBuilder(); builder.AppendLine("/// <summary>"); builder.AppendLine("/// " + subject); builder.AppendLine("/// </summary>"); return builder.ToString(); } } public static class ApiDtoExtensions { public static string ToCSharpClassName(this ApiDto subject) => CSharpIdentifier.ForClassOrNamespace(subject.Name); }
  • 25. System.Text.Json “System.Text.Json is a built-in (de)serializer for .NET Core 3 and beyond.” Developer experience! No extra dependencies needed No dependency on a Newtonsoft.Json that you are not using
  • 26. System.Text.Json Not a 100% replacement for Newtonsoft.Json... https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate- from-newtonsoft-how-to System.Text.Json is extensible enough Custom JsonConverter<T>
  • 28. Code generation & developer experience
  • 29. The ideal “Getting started” 1. Register application in Space 2. Install SpaceDotNet.Client package dotnet add package SpaceDotNet.Client 3. Create connection instance var connection = new ClientCredentialsConnection( "https://your.jetbrains.space/", "client-id", "client-secret", new HttpClient()); 4. Profit!
  • 30. Large API surface var teamDirectoryClient = new TeamDirectoryClient(connection); var birthdays = await teamDirectoryClient .CalendarEvents .BirthdayEvents .GetAllBirthdayEventsAsync(...);
  • 31. Remember $fields ? Top-level fields returned by default Unless $fields query parameter used Use $fields to be specific, or get nested fields
  • 32. $fields Top-level fields returned by default Use partial to be specific, or get nested fields var memberProfile = await teamDirectoryClient.Profiles .GetProfileAsync(ProfileIdentifier.Username("Heather.Stewart")); var memberProfile = await teamDirectoryClient.Profiles .GetProfileAsync(ProfileIdentifier.Username("Heather.Stewart"), _ => _ .WithAllFieldsWildcard() // with all top level fields .WithManagers(managers => managers // include managers .WithId() // with their Id .WithUsername() // and their Username .WithName(name => name // and their Name .WithFirstName() // with FirstName .WithLastName()))); // and LastName
  • 34. Batches (e.g. Get all ToDo items) public class Batch<T> { List<T>? Data { get; } string? Next { get; } int? TotalCount { get; } bool HasNext(); } var batch = await _todoClient.GetAllToDoItemsAsync( from: weekStart.AsSpaceDate(), partial: _ => _ .WithData(data => data // ... .WithTotalCount() .WithNext()); do { foreach (var todo in batch.Data) { // ... } batch = await _todoClient.GetAllToDoItemsAsync( from: weekStart.AsSpaceDate(), skip: batch.Next, partial: _ => _ /* ... */); } while (batch.HasNext());
  • 35. await foreach (var todo in _todoClient .GetAllToDoItemsAsyncEnumerable(from: weekStart.AsSpaceDate(), partial: _ => _ .WithId() .WithContent(content => content .ForInherited<TodoItemContentMdText>(md => md .WithAllFieldsWildcard())) .WithStatus())) { // ... } IAsyncEnumerable to the rescue! ⚠ Don’t use it for .Count() var batch = await _todoClient.GetAllToDoItemsAsync( from: weekStart.AsSpaceDate(), partial: _ => _.WithTotalCount()); var numberOfResults = batch.TotalCount;
  • 37. Request bodies are flattened GetAbsences(AbsencesRequest request) GetAbsences(string member, string reason, ...)
  • 38. Factory methods for inheritors Which option would you prefer? await chatClient.Messages.SendMessageAsync( recipient: new MessageRecipientChannel() { Channel = new ChatChannelFromName() { Name = chatChannelName } }, await chatClient.Messages.SendMessageAsync( recipient: MessageRecipient.Channel(ChatChannel.FromName(chatChannelName)),
  • 39. Default values Unfortunatey not possible in C#... Workaround: Unfortunately not obvious what the default is when not specified. Should we add XMLdoc instead? public async IAsyncEnumerable<AbsenceRecord> GetAllAbsencesAsyncEnumerable( AbsenceListMode viewMode = AbsenceListMode.All, string? member = null) public IAsyncEnumerable<AbsenceRecord> GetAllAbsencesAsyncEnumerable( AbsenceListMode? viewMode = null, string? member = null) => BatchEnumerator.AllItems( () => GetAllAbsencesAsync(viewMode: viewMode ?? AbsenceListMode.All, member: member);
  • 42. Use SpaceDotNet in web apps public void ConfigureServices(IServiceCollection services) { // ... // Space authentication services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = SpaceDefaults.AuthenticationScheme; }) .AddCookie() .AddSpace(options => Configuration.Bind("Space", options)) .AddSpaceTokenManagement(); // auto-refreshes tokens in the background and provides a Space connection // Space client API services.AddSpaceClientApi(); // Space webhook receiver services.AddSpaceWebHookHandler<CateringWebHookHandler>(options => Configuration.Bind("Space", options));
  • 43. Use SpaceDotNet in web apps .AddSpace() Use Space for authN .AddSpaceClientApi() Register ...Client with service collection .AddSpaceTokenManagement() (experimental) Auto-refreshes tokens in the background Space client always auth’ed as currently logged in user .AddSpaceWebHookHandler<T>() (experimental) Webhook support
  • 46. Conclusion JetBrains Space is an Integrated Team Environment JetBrains Space HTTP API exposes everything Building a .NET SDK for the Space HTTP API Goal: make our users succesful at using Space Provide a ready-to-use SDK Minimal configuration needed Discoverability Code generation Focus on developer experience

Editor's Notes

  1. https://pixabay.com
  2. Clear cookies and auth in demo.jetbrains.space! Setup everything to wok with demo.jetbrains.space NGrok running SpaceDotNet opened in Rider
  3. Show home page and mention what is shown (relevat info for me) Show project, mention repo’s, issues, checklists, ... Always possible to annotate and ask questions inline in code. Other folks will see this pop up in chat, so they do not necesarily have to switch context if it’s a minor question. Mention issues, and again, chat integration. Everything can be a to-do as well, use the lightning bolt icon. Automation/CI integrated. Absences integrated is where things get interesting. Who should I contact for certain responsibility? Is that other perso naround to look at my code review? Blogs. Organization-wide, for specific teams or locations. E.g. To share post-mortems, or team announcements, without overloading others. Again, relevant infomation to you. Many other things such as a knowledge base, artifact repo’s for NuGet, NPM, Docker, ...
  4. Show HTTP API playground, send a chat message or something like that. Or get profile info. Mention different endpoints, API’s grouped by functionality Mention request builder, all that, easy to reproduce Show getting a profile, selecting properties, and highlight $fields
  5. Request body as object $fields... Good luck!
  6. Show SpaceDotNet.Generator API model classes, show: ApiEnum, ApiDto, HierarchyRole enumeration Show Program.cs to see how it is bootstrapped Show generated code Show CSharpApiModelEnumGenerator, the simplest of all Mention things are string-based Show the extension methods created (ToCSharpClassName, ToCSharpDeprecation, ...) Show generation adds a custom EnumerationConverter
  7. KotlinPoet in Kotlin SDK
  8. Walk through several of them EnumerationConverter CanConvert -> should be Enumeration Read -> use string, otherwise null Write -> write string value ClassNameDtoTypeConverter CanConvert -> IClassNameConvertible Read We need className from object Then rewind so we can read full class. How to do so? var readerAtStart = reader;  struct gets copied, so we can work with copy to read className Using type map to keep track of types we’re using Write -> Just write the full object
  9. Show SpaceDotNet.Sample.CommandLine Show connection seup Show using TeamDirectoryClient Get pofiles with their name – explain $fields here. No partial -> get top level Partial -> extension methods++ Add .WithFirstName to name, tab, get completion to add it Change code, add: Console.WriteLine($"{profile.Managers[0].Name.FirstName}"); Run, see exception Code generator – show how it’s done CSharpPartialExtensionsGenerator writes the partial extensions Show the effect of FeatureFlags.GenerateBackingFieldsForDtoProperties in generated code Explain C#9 init properties would be nice to use, or even record types, but can we then provide such meaningful error message?
  10. Show CSharpApiModelResourceGenerator GenerateMethodForBatchApiEndpoint, not much special to see Let’s look at generated method instead, e.g. GetAllProfilesAsyncEnumerable Calls into BatchEnumerator.AllItems Show BatchEnumerator.AllItems logic (get page, yield items, get next page, yield results, ...) Side note about [EnumeratorCancellation] Passed in at runtime, used to ensure you can e.g. Enumerate multiple times with different cancellation token ....WithCancellation() at call site
  11. Play with FeatureFlags DoNotExposeRequestObjects – request bodies flattened GenerateInheritorFactoryMethods – factory methods for inheritors GenerateOptionalParameterDefaultReferenceTypes – default values, but will not compile Alternative generates default value checks
  12. Show SpaceDotNet.Samples.Web Show authentication token flow to log in After logging in, show dashboard Index.cshtml is the dashboard Note constructor injection fo e.g. TeamDirectoryClient, and sicne we added Space token management it’s the currently logged in user. Show webhook in action as well In Space itself, converse with webhook In code look at CateringWebHookHandler, mention only few methods need implementing all else is wired up for you Uses MVC under the covers