Successfully reported this slideshow.

Building a friendly Kotlin SDK to connect to JetBrains Space

0

Share

1 of 36
1 of 36

Building a friendly Kotlin SDK to connect to JetBrains Space

0

Share

Download to read offline

Space is a team tool that integrates chats, meetings, git hosting, automation, and much more. It has an HTTP API that lets you integrate third-party apps and workflows. That API is huge, though!

In this session, we will not spend too much time talking about Space. Instead, we'll focus on its API. We'll look at the process, thought, and technology behind the Kotlin SDK for Space, and how we make that massive API more digestible. You will see how we used code generation, domain-specific language, and how building extensibility for third-party developers means you will have to guide them into the pit of success.

Space is a team tool that integrates chats, meetings, git hosting, automation, and much more. It has an HTTP API that lets you integrate third-party apps and workflows. That API is huge, though!

In this session, we will not spend too much time talking about Space. Instead, we'll focus on its API. We'll look at the process, thought, and technology behind the Kotlin SDK for Space, and how we make that massive API more digestible. You will see how we used code generation, domain-specific language, and how building extensibility for third-party developers means you will have to guide them into the pit of success.

More Related Content

More from Maarten Balliauw

Related Books

Free with a 14 day trial from Scribd

See all

Building a friendly Kotlin SDK to connect to JetBrains Space

  1. 1. Building a friendly Kotlin SDK to connect to JetBrains Space Maarten Balliauw @maartenballiauw
  2. 2. Agenda JetBrains Space JetBrains Space HTTP API Building a Kotlin SDK for the Space HTTP API Code generation Developer experience
  3. 3. JetBrains Space
  4. 4. JetBrains Space Integrated Team Environment https://jetbrains.space People Teams Projects - Workspaces for teams Collaboration
  5. 5. JetBrains Space demo
  6. 6. The Space HTTP API
  7. 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. 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 ??? “Open up everything” Large HTTP API surface... HTTP API Playground to explore!
  9. 9. HTTP API Playground demo
  10. 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. 11. Building a Kotlin SDK for the Space HTTP API
  12. 12. Hello, Kotlin! 👋 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. 13. How? Handcrafted No. Over 150 API endpoints Over 700 object types Churn during Space EAP / Space Beta
  14. 14. How? OpenAPI? Use openapi-generator, generate based on OpenAPI / Swagger document Some incompatible object types needed custom code generation
  15. 15. 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!)
  16. 16. Enumeration model class HA_Enum( val id: TID, val name: String, val values: List<String>, val deprecation: HA_Deprecation? ) data class HA_Deprecation( val message: String, val since: String, val forRemoval: Boolean )
  17. 17. Enumeration code generator fun visit(enumType: HA_Enum) = buildString { enumType.deprecation?.let { appendLine("@Deprecated(message = "${it.message}") } val enumClassName = enumType.name.kotlinClassNameJoined() appendLine("enum class $enumClassName {") enumType.values.forEach { appendLine("$it,") } appendLine("}") } enum class AbsenceListMode { All, WithAccessibleReasonUnapproved, WithAccessibleReasonAll }
  18. 18. DTO model class HA_Dto( val id: TID, val name: String, val fields: List<HA_DtoField>, val hierarchyRole: HierarchyRole, val extends: Ref?, val implements: List<Ref>, val inheritors: List<Ref>, val deprecation: HA_Deprecation?, val record: Boolean ) class HA_DtoField(val field: HA_Field, val extension: Boolean) data class HA_Field( val name: String, val type: HA_Type, val deprecation: HA_Deprecation?, val optional: Boolean, val defaultValue: HA_DefaultValue? )
  19. 19. 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)
  20. 20. Custom code generation demo
  21. 21. Strings? KotlinPoet? Generally, a few ways to generate code: String-based Write strings directly Use a template engine Easy to recognize what gets written Model-based KotlinPoet https://square.github.io/kotlinpoet/ Safety (e.g. can’t forget to write class name)
  22. 22. KotlinPoet Kotlin and Java API for generating .kt source files Ensures all properties of code are in place (modifier, type name, ...) Callable references Formatting of generated code https://square.github.io/kotlinpoet/ FunSpec.builder("main") .addStatement("val helloWorld = %L", helloFunction.reference()) .build()
  23. 23. Extension functions everywhere Many places where we need: Kotlin class name from string Kotlin classs from Space model type (Enum/DTO/URL parameter/...) fun String.kotlinClassName(): List<String> = split(".") fun HA_Dto.getClassName() = ClassName("space.jetbrains.api.runtime.types", name.kotlinClassName()) fun HA_UrlParameterOption.getClassName() = ClassName("space.jetbrains.api.runtime.types", optionName.kotlinClassName())
  24. 24. Developer experience
  25. 25. The ideal “Getting started” 1. Register application in Space 2. Add to Gradle file dependencies { implementation "org.jetbrains:space-sdk-jvm:$space_version" } 3. Create connection val spaceClient = SpaceHttpClient(HttpClient()) .withServiceAccountTokenSource( "client-id", "client-secret", "https://your.jetbrains.space/") 4. Profit!
  26. 26. Large API surface
  27. 27. Remember $fields ? Top-level fields returned by default Unless $fields query parameter used Use $fields to be specific, or get nested fields
  28. 28. $fields Top-level fields by default, partial builder to be specific val memberProfile = spaceClient.teamDirectory.profiles .getProfile(ProfileIdentifier.Username("Heather.Stewart")) val memberProfile = spaceClient.teamDirectory.profiles .getProfile(ProfileIdentifier.Username("Heather.Stewart")) { defaultPartial() // with all top level fields managers { // include managers id() // with their id username() // and their username name { // and their name firstName() // with firstName lastName() // and firstName } } }
  29. 29. API playground
  30. 30. Building a chat message... spaceClient.chats.messages.sendMessage( recipient = MessageRecipient.Channel(ChatChannel.FromName(chatChannelName)), content = ChatMessage.Block( style = MessageStyle.SUCCESS, outline = MessageOutline(icon = null, text = "Have you tried JetBrains Space?"), sections = listOf( MessageSection( header = "JetBrains Space", elements = listOf( MessageText(accessory = MessageIcon(ApiIcon("space"), MessageStyle.SUCCESS), content = "JetBrains Space is an Integrated Team Environment."), MessageText(accessory = null, content = "Have you tried JetBrains Space?"), MessageDivider, MessageText(accessory = null, content = "Get access at https://www.jetbrains.com/space/") ), footer = "Check it out at https://www.jetbrains.com/space/" ) ), messageData = null ), unfurlLinks = false )
  31. 31. spaceClient.chats.messages.sendMessage( recipient = MessageRecipient.Channel(ChatChannel.FromName(chatChannelName)), content = message { style = MessageStyle.SUCCESS outline = MessageOutline(icon = null, text = "Have you tried JetBrains Space?") section { header = "JetBrains Space" textWithIcon("JetBrains Space is an Integrated Team Environment.", "space", MessageStyle.SUCCESS) text("Have you tried JetBrains Space?") divider() text("Get access at https://www.jetbrains.com/space/") footer = "Check it out at https://www.jetbrains.com/space/" } }, unfurlLinks = false ) Building a chat message...
  32. 32. Identifiers and factory methods
  33. 33. Developer experience demo
  34. 34. Conclusion
  35. 35. Conclusion JetBrains Space is an Integrated Team Environment JetBrains Space HTTP API exposes everything Building a Kotlin 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
  36. 36. Thank you! https://blog.maartenballiauw.be @maartenballiauw

Editor's Notes

  • https://pixabay.com
  • Clear cookies and auth in demo.jetbrains.space!
    Setup everything to work with demo.jetbrains.space
    space-api-client, space-api-client-samples, and space-app-tutorials open in IJ
  • 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, ...
  • 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
  • Show space-api-client
    API model classes, show: HA_Enum, HA_Dto, HierarchyRole enumeration
    Show Main.kt to see how it is bootstrapped
    Show space/jetbrains/api/generator/GenerateTypes.kt:44
    Using KotlinPoet (more on that later)
    Show the extension methods, like kotlinClassNameJoined() and annotationSpecs.deprecation
  • KotlinPoet in Kotlin SDK
  • Show space-api-client-samples
    Show connection setup
    Show using team directory
    Get profiles with their name – explain $fields here.
    No partial -> get top level
    Partial -> specific, but has code completion
    Show exception case where we help you out (unknown property accessor)
    Chat: show message builder DSL
    Show identifiers with chat
  • ×