ENG
- Services
- Unser Serviceportfolio
Wir erwecken Ihre digitale Produktvision zum Leben: Vom testbaren Prototypen bis zur fertigen Softwarelösung.
- Kooperationsmodelle
Kooperationsmodelle passend zu Ihren Bedürfnissen: Komplette Nearshoring Teams, deutschsprachige Experten vor Ort mit Nearshoring-Teams oder gemischte Teams mit unseren Partnern.
- Arbeitsweise
Durch enge Zusammenarbeit mit Ihrem Unternehmen schaffen wir maßgeschneiderte Lösungen, die auf Ihre Anforderungen abgestimmt sind und zu nachhaltigen Ergebnissen führen.
- Unser Serviceportfolio
- Über uns
- Wer wir sind
Wir sind ein Full-Service Nearshoring-Anbieter für digitale Softwareprodukte, ein perfekter Partner mit deutschsprachigen Experten vor Ort, Ihre Business-Anforderungen stets im Blick
- Unser Team
Das ProductDock Team ist mit modernen Technologien und Tools vertraut und setzt seit 15 Jahren zusammen mit namhaften Firmen erfolgreiche Projekte um.
- Unsere Standorte
Wir sind ProductDock, ein Full-Service Nearshoring-Anbieter für Softwareprodukte mit Hauptsitz in Berlin und Entwicklungs-Hubs in Lissabon, Novi Sad, Banja Luka und Doboj.
- Wozu Nearshoring
Wir kombinieren Nearshore- und Fachwissen vor Ort, um Sie während Ihrer gesamten digitalen Produktreise optimal zu unterstützen. Lassen Sie uns Ihr Business gemeinsam auf das nächste digitale Level anheben.
- Wer wir sind
- Unser Leistungen
- Karriere
- Arbeiten bei ProductDock
Unser Fokus liegt auf der Förderung von Teamarbeit, Kreativität und Empowerment innerhalb unseres Teams von über 120 talentierten Tech-Experten.
- Offene Stellen
Begeistert es dich, an spannenden Projekten mitzuwirken und zu sehen, wie dein Einsatz zu erfolgreichen Ergebnissen führt? Dann bist du bei uns richtig.
- Info Guide für Kandidaten
Wie suchen wir unsere Crew-Mitglieder aus? Wir sehen dich als Teil unserer Crew und erklären gerne unseren Auswahlprozess.
- Arbeiten bei ProductDock
- Newsroom
- News
Folgen Sie unseren neuesten Updates und Veröffentlichungen, damit Sie stets über die aktuellsten Entwicklungen von ProductDock informiert sind.
- Events
Vertiefen Sie Ihr Wissen, indem Sie sich mit Gleichgesinnten vernetzen und an unseren nächsten Veranstaltungen Erfahrungen mit Experten austauschen.
- News
- Blog
- Kontakt

25. Juli 2024 •3 minutes read
Building APIs made easy: From specification to code generation and testing
Jovica Zorić
Chief Technology Officer
APIs (Application Programming Interface) have become one of the most important components of modern digital applications. Whether you’re developing a mobile app that needs to interact with a server, integrating third-party services, or building microservices, a robust and well-designed API is essential. Building APIs can be a challenging task, often involving complex workflows.
In this post, we’ll explore one workflow of API development using TypeSpec and OpenAPI, Golang/Gin, Java/Spring Boot, and Postman, covering the steps from describing our API to testing it.
We will follow these steps:
- Use TypeSpec to describe our API
- Generate OpenAPI specification
- Use code-gen tools to create server-side boilerplate code and add our business logic
- Use Postman to test our API
Before we start, make sure you have:
- Typespec:
npm install -g @typespec/compiler
- oapi-codegen:
go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest
- Postman
Use TypeSpec to describe our API
TypeSpec is a robust tool designed to simplify the API development process by allowing you to define your API specifications in a clear and structured manner. With TypeSpec, you can describe your API endpoints, request parameters, responses, and more in a standardized format.
It is a highly extensible language with primitives that can describe API shapes common among REST, OpenAPI, gRPC, and other protocols. Checkout their documentation and sample specifications.
Our example is an API for managing Events:
@resource("events")
model Event {
@key
id: string;
@doc("The name of the event")
name: string;
@doc("The scheduled date and time of the event")
date: utcDateTime;
@doc("Information about the venue where the event will be held")
location: Location;
}
model Location {
name: string;
}
@doc("Error")
@error
model EventError {
code: int32;
message: string;
}
@service({
title: "Event Service",
})
@versioned(Versions)
namespace EventService;
@route("/events")
@tag("Events")
interface Events {
@added(Versions.v1)
op create(@body event: Event): Event | EventError;
@added(Versions.v1)
op findByNameFuzzy(@query name: string): Event[];
@added(Versions.v1)
op read(@path id: string): Event;
@delete
@added(Versions.v1)
op delete(@path id: string): void;
}
enum Versions {
v1,
}
As we can see, reading TypeSpec is straightforward, and even though writing the spec in VS Code is all right, I’m missing other editors’ support. Hopefully, this will change in the future. Here, in the Events interface, I used basic CRUD operations.
What is also interesting is that TypeSpec has Interfaces and Operations templates that can be used to describe the APIs even faster. Check this example from the petstore sample.
Generate OpenAPI specification
Having described our API spec, we can use the TypeSpec compiler/CLI to generate an OpenAPI spec file. We want OpenAPIv3, so we will use the OpenAPI3 emitter. Let’s run: tsp compile and see our OpenAPIV3 specification.
openapi: 3.0.0
info:
title: Event Service
version: v1
tags:
- name: Events
paths:
/events:
post:
tags:
- Events
operationId: Events_create
parameters: []
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
default:
description: An unexpected error response.
content:
application/json:
schema:
$ref: '#/components/schemas/EventError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
get:
tags:
- Events
operationId: Events_findByNameFuzzy
parameters:
- name: name
in: query
required: true
schema:
type: string
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Event'
/events/{id}:
get:
tags:
- Events
operationId: Events_read
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: The request has succeeded.
content:
application/json:
schema:
$ref: '#/components/schemas/Event'
delete:
tags:
- Events
operationId: Events_delete
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'204':
description: 'There is no content to send for this request, but the headers may be useful. '
components:
schemas:
Event:
type: object
required:
- id
- name
- date
- location
properties:
id:
type: string
name:
type: string
description: The name of the event
date:
type: string
format: date-time
description: The scheduled date and time of the event
location:
allOf:
- $ref: '#/components/schemas/Location'
description: Information about the venue where the event will be held
EventError:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
description: Error
Location:
type: object
required:
- name
properties:
name:
type: string
Versions:
type: string
enum:
- v1
Use code-gen tools to create server-side boilerplate code and add our business logic
We will use code generation tools to reduce the boilerplate required to create code based on OpenAPI and instead focus on writing the business logic. Examples are in Golang/Gin and Java/Spring Boot. Here I’ll write the building blocks while you can find the complete code in the github repository.
Golang/Gin
First install oapi-code gen:
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest and create the config file.
events.gen.yml
package: api
generate:
models: true
gin-server: true
output: events.gen.go
Use go generate directive:
events.go
//go:generate oapi-codegen --config=events.gen.yml ../../tsp-output/@typespec/openapi3/openapi.v1.yaml
package api
....
Run: go generate ./… to generate the code.
After boilerplate code is generated, we need to implement our server interface (our handlers):
// ServerInterface represents all server handlers.
type ServerInterface interface {
// (GET /events)
EventsFindByNameFuzzy(c *gin.Context, params EventsFindByNameFuzzyParams)
// (POST /events)
EventsCreate(c *gin.Context)
// (DELETE /events/{id})
EventsDelete(c *gin.Context, id string)
// (GET /events/{id})
EventsRead(c *gin.Context, id string)
}
Check the example implementation. I used Intellij for a quick “implement this interface” function.
Java/Spring Boot
In the Maven project, first add these two dependencies:
<!-- https://mvnrepository.com/artifact/org.openapitools/jackson-databind-nullable -->
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.8.0</version>
</dependency>
And use the openapi-generator-maven-plugin:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.6.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>../tsp-output/@typespec/openapi3/openapi.v1.yaml</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>com.productdock.openapi.api</apiPackage>
<modelPackage>com.productdock.openapi.model</modelPackage>
<generateSupportingFiles>false</generateSupportingFiles>
<configOptions>
<skipDefaultInterface>true</skipDefaultInterface>
<delegatePattern>false</delegatePattern>
<interfaceOnly>true</interfaceOnly>
<library>spring-boot</library>
<oas3>true</oas3>
<useSpringController>false</useSpringController>
<!-- javax.* to jakarta.* -->
<useSpringBoot3>true</useSpringBoot3>
<useSpringfox>false</useSpringfox>
<apiFirst>false</apiFirst>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
Run: ./mvnw clean compile to generate the code.
For the implementation, we can create a Spring boot controller by implementing the EventsAPI interface.
Use Postman to test our API
Before you start testing the API, remember to run the server API, which will be running on port 8084.
Using portman run:
npx @apideck/portman -l tsp-output/@typespec/openapi3/openapi.v1.yaml -o events-postman-collection.json -b http://localhost:8084 -t false
This will generate an events-postman-collection.json file which you can import to Postman and start testing your APIs.
The straightforward workflow has helped me build proof-of-concepts and walking skeletons. Besides editor support, I really enjoyed this design-first approach with TypeSpec. Looking forward to their next milestones.
> What’s your approach to defining APIs? What tools are you using?
Tags:
Jovica Zorić
Chief Technology OfficerJovica is a techie with more than ten years of experience. His job has evolved throughout the years, leading to his present position as the CTO at ProductDock. He will help you to choose the right technology for your business ideas and focus on the outcomes.