---
id: e10df2108115b462a5ac2a289080a901
author: iwanhae
title: Go og OpenAPI-økosystemet
description: Vi presenterer biblioteker og strategier som kan brukes ved utvikling av OpenAPI-baserte API-er med Go-språket.
language: "no"
date: 2024-10-18T06:07:43.092628696Z
path: /blog/posts/go-and-the-openapi-ecosystem-zd5a8e472
category: api
---

### Innledning

Når man utvikler en Production Backend-server med Go, står nesten alle utviklere tidligt overfor et av de første vanskelige problemene, nemlig:

> API-dokumentasjon, hvordan skal vi gjøre dette...?

Ved å søke litt finner man ut at det er nyttig å skrive dokumentasjon i samsvar med OpenAPI-spesifikasjonen, og man begynner naturlig nok å lete etter biblioteker som integreres med OpenAPI. Men selv etter at denne avgjørelsen er tatt, oppstår neste problem.

> Det finnes mange OpenAPI-relaterte biblioteker... hvilket skal jeg bruke...?

Dette dokumentet er en kort introduksjon til biblioteker, skrevet for Go-nybegynnere som står i denne situasjonen. Det er utarbeidet per slutten av 2024, og da økosystemet for programmeringsspråk stadig endrer seg, anbefales det å bruke dette som referanse og samtidig holde seg oppdatert på de nyeste utviklingene.

### Strategier for OpenAPI i bibliotekene

Dette er sannsynligvis kjent for deg allerede, men OpenAPI er en spesifikasjon for å definere og dokumentere REST API-er på en tydelig måte. Ved å definere API-ets endepunkter, forespørsler og responsformater i YAML- eller JSON-format, hjelper det betydelig både utviklere og kode for frontend og backend ved å automatisere kodegenerering, redusere meningsløs repetisjon og minske mindre menneskelige feil.

For å integrere OpenAPI naturlig i prosjektet bruker bibliotekene i Go-økosystemet i hovedsak følgende tre strategier.

#### 1. Sammensetning av OpenAPI-spesifikasjonsdokumenter fra Go-kommentarer

En vanskelig side ved å utvikle API-er i henhold til OpenAPI er at selve dokumentasjonen og koden som implementerer den ligger i separate filer på helt ulike steder. Det er ganske ofte at koden oppdateres uten at dokumentet oppdateres, eller at dokumentet oppdateres uten at koden blir oppdatert.

Et enkelt eksempel:

1. Du endrer API-logikken i filen `./internal/server/user.go`
2. Den faktiske dokumentasjonen ligger i `./openapi3.yaml`, og du kan ved en feil glemme å endre den.
3. Hvis du ikke oppdager dette problemet, sender du en Pull Request og får gjennomgang fra kollegaene.
4. Også reviewerne ser ikke endringene i `./openapi3.yaml`, så det kan skje at API-spesifikasjonen forblir den samme, mens den faktiske API-implementasjonen har endret seg.

Ved å skrive API-dokumentasjon som Go-kommentarer kan man løse dette problemet i en viss grad. Fordi kode og dokumentasjon ligger på ett sted, kan man oppdatere kommentarene samtidig som man endrer koden. Det finnes verktøy som automatisk genererer OpenAPI-spesifikasjonsdokumenter basert på disse kommentarene.

Et representativt prosjekt er [Swag](https://github.com/swaggo/swag). Swag analyserer kommentarene i Go-koden og genererer dokumentasjon i OpenAPI 2-format. Bruken er enkel: Du skriver kommentarer over behandlerfunksjonen i formatet som er definert av biblioteket.

```go
// @Summary 유저 생성
// @Description 새로운 유저를 생성합니다.
// @Tags Users
// @Accept json
// @Produce json
// @Param user body models.User true "유저 정보"
// @Success 200 {object} models.User
// @Failure 400 {object} models.ErrorResponse
// @Router /users [post]
func CreateUser(c *gin.Context) {
    // ...
}
```

Når kommentarene er skrevet slik, analyserer Swag-CLI-en disse kommentarene og genererer et OpenAPI 2-dokument. Vanligvis utføres dette i CI-prosessen, og det genererte OpenAPI-spesifikasjonsdokumentet publiseres i Git-repositoriet, i de endelige byggeresultatene eller i et eksternt system for administrasjon av API-dokumentasjon, slik at det kan brukes i samarbeid med andre prosjekter.

**Fordeler:**

- Fordi kommentarene ligger sammen med koden, **er det mindre sannsynlig at den faktiske kodens form og dokumentasjonen avviker.**
- Uten egne verktøy eller komplisert oppsett kan man **dokumentere enkelt og fritt** med kun kommentarer.
- Kommentarene påvirker ikke den faktiske API-logikken, så det er **godt egnet for å legge til midlertidige funksjoner som man ikke ønsker å eksponere i dokumentasjonen.**

**Ulemper:**

- Når antall kommentarlinjer øker, **kan lesbarheten til en enkelt kodefil bli dårligere.**
- Det kan **være vanskelig å uttrykke alle API-spesifikasjoner med kommentarer.**
- Dokumentasjonen tvinger ikke koden til å samsvare med den, så det **finnes ingen garanti for at OpenAPI-dokumentasjonen og den faktiske logikken er konsistente.**

## 2. Generering av Go-kode fra OpenAPI-spesifikasjonsdokumenter

Det finnes også en metode der Single Source of Truth (SSOT) plasseres i dokumentet i stedet for i Go-koden. Man definerer først OpenAPI-spesifikasjonen, og genererer deretter Go-kode basert på det som er definert. Fordi API-spesifikasjonen genererer koden, kan man i utviklingskulturen håndheve at API-designet gjøres først. Siden definisjonen av API-spesifikasjonen er det første som gjøres i utviklingsrekkefølgen, har denne metoden den styrken at man tidlig kan forhindre at man oppdager manglende deler først etter at utviklingen er ferdig, og at hele koden må endres sammen med endringer i API-spesifikasjonen.

Representative prosjekter som bruker denne metoden er [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) og [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator/tree/master/samples/server/petstore/go-echo-server). Bruken er enkel.

1. Skriv et YAML- eller JSON-dokument i samsvar med OpenAPI-spesifikasjonen
2. Kjør CLI-en
3. Tilsvarende Go-stub-kode genereres
4. Nå trenger du bare å implementere den detaljerte logikken for hvert enkelt API, slik at stub-koden kan brukes

Følgende er et eksempel på kode generert av oapi-codegen.

```go
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
	// ...
	// Returns all pets
	// (GET /pets)
	FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
	// ...
}
```

Koden som oapi-codegen genererer basert på dette interfacet, utfører logikk for parsing og validering av query-parametere, headere og body, og kaller deretter den passende metoden som er deklarert i interfacet. Brukeren trenger bare å implementere en konkret type for dette interfacet, så er arbeidet som kreves for API-implementasjonen fullført.

**Fordeler:**

- Fordi **spesifikasjonen kommer først og utviklingen skjer deretter**, er det gunstig for flere team som samarbeider, å **utføre arbeidet parallelt**.
- Kode for det som tidligere var repetitivt manuelt arbeid, **genereres automatisk**, så **arbeidseffektiviteten øker**, samtidig som det fortsatt er **gunstig for feilsøking**.
- Det er enklere å **garantere at dokumentasjon og kodeform alltid samsvarer**.

**Ulemper:**

- For de som ikke kjenner OpenAPI-spesifikasjonen godt, **finnes det en viss innledende læringskurve**.
- Formen på koden som håndterer API-et genereres automatisk av prosjektet, så det **kan være vanskelig å håndtere tilfeller som krever tilpasning**.

> Forfatterens kommentar.
> Per oktober 2024 genererer OpenAPI Generator Go-kode som ikke bare begrenser API-logikken, men hele prosjektstrukturen, og den genererte koden har en stiv struktur som gjør den lite egnet for å legge til de ulike funksjonene som trengs i et faktisk produksjonsmiljø. For dem som velger denne metoden, anbefales det sterkt å bruke oapi-codegen. Forfatteren bruker oapi-codegen + echo + StrictServerInterface.

## 3. Generering av OpenAPI-spesifikasjonsdokumenter fra Go-kode

Når dziesiątki, hundrevis av mennesker utvikler på samme server, oppstår nødvendigvis det problemet at konsistensen mellom de enkelte API-ene kan brytes. Et tydelig eksempel: Hvis spesifikasjonen for over 100 API-endepunkter deklareres i en enkelt OpenAPI YAML-fil, vil filen bli et monster på over 10 000 linjer. Når nye API-endepunkter legges til, vil samme modell nødvendigvis bli deklarert flere ganger, noen felt vil bli utelatt, eller det vil oppstå stinamn som ikke følger konvensjonene. Dermed begynner den helhetlige konsistensen i API-et å bryte sammen.

For å løse dette kan man utpeke en eier som administrerer OpenAPI YAML-filen, eller utvikle en linter og sørge for at den fanger opp problemer automatisk under CI-prosessen. Man kan også bruke Go til å definere et Domain-specific language (DSL), slik at alle API-er tvinges til å ha en enhetlig konsistens.

Et representativt prosjekt som bruker denne teknikken er Kubernetes, som bygger dette selv uten eksterne biblioteker. Man kan også prøve prosjekter som [go-restful](https://github.com/emicklei/go-restful) og [goa](https://goa.design/). Følgende er et eksempel på bruk av `goa`.

```go
var _ = Service("user", func() {
    Method("create", func() {
        Payload(UserPayload)
        Result(User)
        HTTP(func() {
            POST("/users")
            Response(StatusOK)
        })
    })
})
```

Når man skriver kompilerbar Go-kode slik som dette, får man den styrken at implementasjonen av `POST /users`-API-et og definisjonen av dokumentasjonen fullføres samtidig.

**Fordeler:**

- Fordi alt genereres fra koden, **er det enkelt å opprettholde API-konsistens for hele prosjektet**.
- Ved å utnytte Gos sterke typesystem kan man få **en mer presis og mindre omstridt spesifikasjon** enn ved å bruke alle funksjonene i OpenAPI3.

**Ulemper:**

- **Man må lære DSL-en som hvert rammeverk har definert**, og det **kan være vanskelig å anvende på eksisterende kode**.
- Fordi man må følge reglene som rammeverket foreslår, **kan frihet og fleksibilitet bli redusert**.

**Avslutning**

Hver metode har sine fordeler og ulemper, og det er viktig å velge den metoden som passer best til prosjektets krav og teamets preferanser. Det viktigste er ikke hvilken metode som er best, men å vurdere hvilken løsning som passer best for din egen situasjon, og å øke utviklingsproduktiviteten slik at du kan få **tidlig fyraften** og **god balanse mellom arbeid og fritid**.

Selv om artikkelen er skrevet med utgangspunkt i oktober 2024, utvikler økosystemene for Go og OpenAPI seg kontinuerlig. Ta hensyn til tiden som har gått siden du leser dette, og følg fortsatt med på nyheter og endrede for- og ulemper ved de enkelte bibliotekene og prosjektene.

Lykke til med Go-livet 😘
