Create a REST API Using Swagger in Go Part 2

This is the second part of a three-part series about creating a REST API in Go. If you have not read Part 1, feel free to check that out here.

Picking Up Where We Left Off

If you’re coming from part 1 of this tutorial, after installing Swagger and editing our config file, we generated the endpoint code and are ready to use it. The beauty of this generated code is you rarely have to worry about it since its all managed by the swagger library. What we need to watch out for is our config file because that’s the source of the generation. Let’s go over what some of it does really quick though.

  • operations/<swagger-project-name>-api.go – This is the actual code representation of our API that is passed into server.go
  • server.go – This file creates our API server without the configurations. We handle configurations through another file.
  • embedded_spec.go – This is a string version of our entire swagger.yaml config file to be used at runtime.
  • doc.go – A simple metafile.
  • configure_<swager-project-name>.go – This is one of the files that allow us to configure our server. With each endpoint we declare in our config file, code can be generated that will allow us to define what happens when those endpoints.

The remaining files are the boilerplate of the actual endpoint itself, including middleware, request/response structs needed to serialize data, and more.

Hooking Up The First Endpoint

With our swagger code generated, we are able to launch the api with a few lines. Open up main.go and paste this inside the main function:

var questions []Question
swaggerSpec, err := loads.Analyzed(
  restapi.FlatSwaggerJSON,
  "2.0",
)
if err != nil {
  log.Fatal(err)
}

This will analyze the server according to what we have in swagger.yml as well as initialize our list of Questions. Next, we need to create a struct to help pass trivia data to and from the API. Add the following struct above the main function:

type Question struct {
  Question string
  Answer   string
  Category string
}

Typically an endpoint like this would write to a database, but we’re just gonna use a list of Questions as our database to keep the tutorial simple. Lastly, we’ll write the code that will initialize the server as well as handle the incoming data.

api := operations.NewATriviaApplicationAPI(swaggerSpec)

Passing our swaggerSpec object into the function NewATriviaApplicationAPI allows us to initialize our api object. This function was generated during the swagger command which is really cool because we don’t have to worry about it. And finally, we’ll add the function that will receive the incoming data for endpoint and add it to a list of questions:

api.PostQuestionHandler = operations.PostQuestionHandlerFunc(
  func(p operations.PostQuestionParams) middleware.Responder {

     q := Question{
        Question: p.Body.Question,
        Answer:   p.Body.Answer,
        Category: p.Body.Category,
     }

     questions = append(questions, q)

     return operations.NewPostQuestionOK().WithPayload(&operations.PostQuestionOKBody{
        Message: "Question added!",
     })
  },
)

Let’s start with api.PostQuestionHandler, it is being set to a function named PostQuestionHandlerFunc. This function was also generated with the swagger command, and within it gets passed another function where we implement what our app will do once the data is received via the endpoint. 

This anonymous function takes a parameter named p of type PostQuestionParams. PostQuestionParams also comes from the generated code and is basically a struct made up of fields from the request body we specified in swagger.yml. 

As you can see we use those fields to create a Question, q. Now we can append it to our slice of questions that was initialized earlier. Lastly, we’ll return an HTTP code of 200 with a success message!

We’ve only got a few more things to set up before we can run the app. We’ll set the port we want to communicate on and create a server object with the help of our api object, along with some other boilerplate stuff.

srv := restapi.NewServer(api)
srv.EnabledListeners = []string{"http"}
srv.Port = 8080

defer func() {
  log.Println("shutting down...")
  srv.Shutdown()
}()

log.Println("starting server...")

if err := srv.Serve(); err != nil {
  log.Panicln("server err:", err)
}

Here, we create a server object named srv. Next we set our listening protocol to HTTP and communication port to 8080. Next we are deferring the shutdown code by using a special keyword in go, defer. When used, the lines within the defer function are evaluated immediately, but they don’t actually get executed until later. 

Finally, we print a message to the log that will let us know the server is starting and we call the Serve() function to officially server our API over the internet. Start this app, open up any web browser, and visit the following web address:

localhost:8080/docs

You should see some documentation like so:

documentation generated from swagger.yml

Pretty cool right?! More documentation will appear as we add to our config file, but let’s use what we have for now. Open up a terminal and copy the following:

curl --location --request POST 'localhost:8080/question' \
--header 'Content-Type: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
  "answer": "100mph",
  "category": "Health",
  "question": "How fast do sneezes travel?"}'

This will create a POST call to our app that will add a question asking how fast do sneezes travel. It will also have a category of Health within our trivia app. Lastly we see the success message from our code which lets us know that the call was successful!

This brings us to the end of the second part of this tutorial. For the final part, we’ll add a few more endpoints and go over how we can make managing our generated code even easier with a Makefile. 

Thanks for reading this article and don’t forget to subscribe to our email list for updates on future posts!

Leave a Comment

Your email address will not be published. Required fields are marked *