Tutorials on Rest Api

Learn about Rest Api from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

RESTful API Documentation with Go and chi docgen Package

An important chore that gets neglected by developers is writing documentation for their RESTful APIs. Often, this task ends up being assigned lower priority than other tasks, such as building a new feature or modifying an existing feature. Although it delivers no immediate tangible value to end users like features, documentation produces intangible value for developers and their companies. By having detailed information about a RESTful API's endpoints, developers can quickly know how to obtain authorization for protected endpoints, access and interact with certain resources, format the data that's required in a request's body, etc. Ultimately, the value in documentation comes from increased developer productivity and saved development time. The more developers the documentation serves, the more value the documentation produces. Fortunately, you don't have to spend any time or effort to manually build and maintain documentation from scratch. There are open source tools like Swagger that automate the process of designing and generating RESTful API documentation for developers. These tools: Best of all, most of these tools only need, as input, the source code of the RESTful API or a JSON representation of the RESTful API that's compliant with the OpenAPI Specification . Or, these tools can get fed other representations of the RESTful API that are based on alternative API specifications like RAML ( R ESTful A PI M odeling L anguage). After generating the documentation, all that's left is to host and share the documentation. If you built your RESTful API with the Go chi library, then you can automatically generate routing documentation with one of its optional subpackages: docgen . Below, I'm going to show you how to leverage docgen to: To get started, clone the following repository to your local machine: This repository contains source code for a simple RESTful API built with Go and chi . The router uses a middleware stack that consists of the following middlewares: Additionally, render.SetContentType(render.ContentTypeJSON) forces the Content-Type of responses to be  application/json . Most of these middlewares are ported from Goji , a minimalistic web framework for Go, and they are built with native Go packages. The router defines several endpoints for a resource that represents posts: To start up the RESTful API, first install the project's dependencies. Then, compile and execute the code. docgen lets you print a list of available routes to STDOUT at runtime, like so: This gives an overview of the resources that can be accessed from this RESTful API. To log routing documentation to STDOUT, first add the github.com/go-chi/docgen dependency to the list of imported packages and dependencies in main.go , like so: Note #1 : If you encounter the error message cannot use r (variable of type *"github.com/go-chi/chi".Mux) as type "github.com/go-chi/chi/v5".Routes in argument to docgen.JSONRoutesDoc: , then you should change the imported dependency from github.com/go-chi/chi to "github.com/go-chi/chi/v5 . Note #2 : If you encounter the error message http: panic serving 127.0.0.1:50114: runtime error: slice bounds out of range [-1:] , then you should change the imported dependency from github.com/go-chi/chi/middleware to github.com/go-chi/chi/v5/middleware . Then, inside of the main() function, call the method docgen.PrintRoutes() after mounting the sub-router defined on the postsResource struct to the main router, like so: Stop the RESTful API service and re-run the following commands to install the newly added dependency ( github.com/go-chi/docgen ) and restart the RESTful API service: Now, the RESTful API's routes get logged to STDOUT. Since documentation should be shared with other developers, let's output the routing information to a pre-formatted Markdown document. Using the docgen.MarkdownRoutesDoc() method, docgen crawls the router to build a route tree. For each route and subroute, docgen collects: Then, using this tree, docgen structures and outputs the Markdown as a string. docgen will link each middleware and handler function to its implementation in the source code (the file and line where the implementation can be located). The docgen.MarkdownRoutesDoc() method accepts two arguments: Note : Any fields omitted from the struct are zero-valued. Unlike logging the route documentation to STDOUT, the Markdown should not be generated every time the RESTful API service starts up, especially if you want to write the stringified Markdown to a separate file. Instead, let's generate the Markdown only when the user passes a specific flag to the go run command. First, let's add the flag and errors packages to the list of imported packages and dependencies in main.go , like so: Just before the main() function, declare a string flag docs with a default value of an empty string (second argument) and a short description (third argument). Note : This flag will support three values: markdown , json and raml . -docs=markdown will output the routing information to a pre-formatted Markdown document, while -docs=json and -docs=raml will output JSON and RAML representations of the RESTful API respectively. We will implement the json and raml flag values in the next section of this tutorial. At the start of the main() function body, call the flag.Parse() method to parse the command-line flags into any flags defined before the main() function. At the end of the main() function body, after calling the docgen.PrintRoutes() method, check if the docs flag has been set to markdown . If so, then call the docgen.MarkdownRoutesDoc() method to generate the Markdown and write it to a routes.md file, like so: Note #1 : f, err := os.Create("routes.md") does not follow the same pattern as the other conditional statements (of having a declaration precede conditionals). Otherwise, f.Close() would cause the error undefined: f since f would only be scoped to its corresponding conditional statement's branches. For the statement to follow the same pattern as the other conditional statements, you would need to declare the variables f and err outside and replace the short declaration with a standard assignment. Note #2 : Even if the routes.md file does not exist, os.Remove will return an error remove routes.md: no such file or directory . Therefore, to prevent this error from causing the program to exit, check that the error is not an os.ErrNotExist error via the errors.Is() method. Now, add a new rule to the Makefile that compiles and executes the code with the -docs=markdown flag. ( Makefile ) Also, add the following code to the top of the Makefile so that docgen can detect the GOPATH environment variable when the go run command is executed via a make command. ( Makefile ) Note : Without this, you will encounter the error message ERROR: docgen: unable to determine your $GOPATH . When you run the make command with the target gen_docs_md , Go generates the routing documentation in Markdown and outputs it to a routes.md file: Below is what the Markdown file should look like. The bulleted middleware and handler functions link directly to their implementation in the source code (file and line). ( routes.md ) Having JSON and RAML representations of a RESTful API gives other software and tools the ability to understand the RESTful API's endpoints, middleware stack, etc. These representations can be consumed to create beautiful, custom UIs for displaying the documentation, build testing and scaffolding tools, etc. The APIs provided by docgen for generating JSON and RAML representations of the RESTful API are quite different. Therefore, let's start with the much simpler task of generating the JSON representation of the RESTful API. In the main() function, add another conditional branch ( else if statement) to the conditional statement *docs == "markdown" that checks if the docs flag is set to json . If so, then call the docgen.JSONRoutesDoc() method to generate the JSON representation and write it to a routes.json file, like so: Now, add a new rule to the Makefile that compiles and executes the code with the -docs=json flag. ( Makefile ) When you run the make command with the target gen_docs_json , Go generates the JSON representation and outputs it to a routes.json file: Below is what the JSON file should look like. The JSON data organizes the routes in a hierarchical order and contains information like the different HTTP methods allowed for a given route, the handler function and middleware stack that's called for a given endpoint, the location of the handler function in the source code, any comments written above the handler function's definition, etc. ( routes.json ) Note : Although the JSON representation of the RESTful API that's generated by docgen does not fully adhere to the OpenAPI specification , you can still apply a few transformations to make it compliant and work with tools like Swagger UI. For the RAML representation, we need to add the strings package and two more dependencies to the list of imported packages and dependencies in main.go : Then, in the main() function, add another conditional branch ( else if statement) to the conditional statement *docs == "markdown" that checks if the docs flag is set to raml . If so, then perform the following steps to generate the RAML representation of the RESTful API: Note : The fields in the raml.RAML struct come directly from the RAML specification, and they describe some of the basic aspects of the RESTful API like its title and version. This information ends up in the root section of the outputted RAML document. If you are not familiar with RAML, then please visit the RAML documentation . Now, add a new rule to the Makefile that compiles and executes the code with the -docs=raml flag. ( Makefile ) Stop the RESTful API service and install the newly added dependencies. When you run the make command with the target gen_docs_raml , Go generates the RAML representation and outputs it to a routes.raml file: Below is what the RAML file should look like. Notice how docgen organizes the routes in a similar hierarchical order like what's seen in the JSON representation of the RESTful API, but in a YAML-based format. To turn this RAML file into an interactive, documentation UI that can be shared with others, let's use the raml2html HTML documentation generator. You can install raml2html globally via npm and run its CLI tool to generate the documentation UI from RAML. However, if you do not want to install raml2html globally on your local machine, then you can also run a Dockerfile that containerizes raml2html . Run the following docker command to run the raml2html CLI tool in a new container, giving it the routes.raml file as an input and having it output a routes.raml.html file. Note : If you encounter the error message docker: Error response from daemon: Mounts denied: The path <full_project_directory_path> is not shared from the host and is not known to Docker. You can configure shared paths from Docker -> Preferences... -> Resources -> File Sharing. , then you should add the full path of the project directory (whatever gets printed by the pwd ) to the list of directories that can be bind mounted into Docker containers. After that's completed, open a new terminal session and re-run the docker command. Once the routes.raml.html file is generated (located in the root of the project directory), open this file in a browser to see the documentation UI. If you find yourself stuck at any point while working through this tutorial, then feel free to visit the main branch of this GitHub repository here for the code. Explore and try out other automated documentation solutions. If you want to learn more advanced back-end web development techniques with Go, then check out the Reliable Webservers with Go course by Nat Welch, a site reliability engineer at Time by Ping (and formerly a site reliability engineer at Google), and Steve McCarthy, a senior software engineer at Etsy.

Thumbnail Image of Tutorial RESTful API Documentation with Go and chi docgen Package

Benchmarking a Go and chi RESTful API

The amount of time and effort a developer dedicates towards writing a function depends on the details they choose to focus on: coding conventions, structure, programming style, etc. Suppose a group of developers is presented a high-level prompt to write the same function: given some input, return some output. For example, given a list of numbers, return a sorted list of numbers. The actual implementation of the function is left entirely to the discretion of the developer. A quick, mathematical way to evaluate each developer's implementation of this function, without any additional code, is by its time complexity . Particularly, knowing each implementation's Big-O complexity tells us how it might perform in the worst case scenario, commonly when the size of the input is very large. However, time complexity fails to account for the hardware the function is executed upon, and it does not provide any tangible, quantifiable metrics to base decisions on. Metrics such as operation speed and total execution time assign real numerical values to the performance of a function. By adding benchmarks , developers can leverage these metrics to better inform them on how to improve their code. The Go programming language has a benchmarking utility in its built-in, standard library package testing . To benchmark code in Go, define a function with a name prefixed with Benchmark (followed by a capitalized segment of text) and accepts an argument of struct type B , which contains methods and values for determining the number of iterations to run, running multiple benchmarks in parallel, timing execution times, etc. Example : Note : The structure of a benchmark is similar to the structure of a test. Replace Test with Benchmark and t *testing.T with b *testing.B . This benchmark runs the Sum function for b.N iterations. Here, the benchmark runs for one billion iterations, which allows the benchmark function to reliably time and record each execution. Once the benchmark is completed, the results of this benchmark and the CPU of the machine running this benchmark are outputted to the terminal. On average, each iteration ran 0.6199 ns. Below, I'm going to show you... Clone a copy of the Go and chi RESTful API from GitHub to you machine: This RESTful API specifies five endpoints for performing operations on posts: If you would like to learn how to build this RESTful API, then please visit this blog post . In the basic-tests branch, a simple unit test is already provided in the routes/posts_test.go file. Because benchmarks must be placed in _tests.go files, let's place the benchmarks for the posts sub-router in the routes/posts_test.go file. Run the following command to install the project's dependencies: Note : If you run into installation issues, then verify that the version of Go running on your machine is v1.16 . Run the following command to execute the unit tests within the routes/posts_test.go file: To get started, open the routes/posts_test.go file. Let's name the benchmark function BenchmarkGetPostsHandler : Combine the code snippets together: ( routes/posts_test.go ) Run the benchmark: Here, benchmarks run sequentially. The benchmark ran a total of 97220 iterations with each iteration running, on average, 11439 ns. This represents the average time it took for each handler.ServeHTTP function (and by extension, PostsResource{}.List ) call to complete. Each iteration involved the allocation of, on average, 33299 bytes of memory. Memory was allocated, on average, 8 times per iteration. The for loop forces the benchmark to execute the function handler.ServeHTTP sequentially, one after the other. By running the benchmark with b.RunParallel , the total iterations b.N is divided amongst the machine's available threads (distributed amongst multiple goroutines). Having these iterations run concurrently helps to benchmark code that's inherently concurrent, such as sending requests and receiving responses, and deals with mutexes and/or shared resources. To parallelize benchmarks, wrap the benchmark code in b.RunParallel and replace the for loop with for pb.Next() : ( routes/posts_test.go ) Run the benchmark again. Notice that the benchmark values are similar to when we ran the benchmark sequentially with a for loop. To increase the number of cores (and goroutines) to run this benchmark against, add the cpu flag: Increasing the number of cores increases the number of goroutines running the benchmark iterations, which results in better performance. Click here for a final version of the route handler unit test. Try writing benchmarks for the other route handlers.

Thumbnail Image of Tutorial Benchmarking a Go and chi RESTful API

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

5 Minute Intro to REST APIs

Learn the basics of APIs and what makes an API "RESTful"So what is an API (Application Programming Interface)? It's pretty simple from a high-level — two applications interfacing (or “talking”) with each other via programs. APIs also make our lives easier by abstracting away complex code and replacing it with simpler, more straightforward code. For example, think about what happens when you open a music streaming app and play a song. There's probably some code that runs when you hit play that looks something like this: That play() function is an API method that abstracts away things like: As developers, we don't need to know or care about the lower-level code when we call the play() method, and that's fine! APIs are here to make our lives easier. In JavaScript, APIs are usually based on objects . In the example above, the mediaPlayer object is the entry point for the API, and play() is the API method . Let's take a look at a more common example you've probably encountered before. If you've ever written JavaScript like this: then congrats, you've used the DOM (Document Object Model) API ! Here, the document object is being used as the entry point for the DOM API, and querySelector() is the API method . In the web development world, APIs generally fall into two categories: So if an API is a set of rules that allow one piece of software to talk to another, then REST (Representational State Transfer) is a standard set of rules that developers follow to create an API. Six conditions that need to be met for an API to be considered RESTful: I think you’d be hard-pressed to find anyone who remembers the definition of each of these conditions off the top of their head, so the gist of it is this: In a nutshell, you should be able to receive a piece of data (a.k.a.  resource ) when you access a predefined URL. Each of these URLs, also known as “ endpoints ", are part of what is called a request , and the data you receive from the request is called a response . The data provided by these responses are usually in the form of JSON ( JavaScript Object Notation ). A RESTful request is composed of four parts: Let’s take a quick look at what each of these four parts are. The "endpoint" is the URL you request. All REST APIs have a base URL (also known as the "root" endpoint). For example, the base URL of Spotify's API is https://api.spotify.com while the base URL of GitHub's API is https://api.github.com . Additionally, each endpoint in a REST API has a path that determines the resource being requested. In the example endpoint above, https://api.spotify.com/v1 is the base URL, and /playlists/59ZbFPES4DQwEjBpWHzrtC is the path to a particular playlist. The HTTP method is the type of request you send to the server. There are five common types of HTTP methods: GET , POST , PUT , PATCH , and DELETE . They are used to perform four possible operations: Create, Read, Update, or Delete (CRUD). When working with a REST API, the documentation should tell you which HTTP method to use with each request. Headers are key-value pairs that are used to provide information to both the client and server. You can store things like authentication tokens, cookies, or other metadata in HTTP headers.  For example, the header below tells the server to expect JSON content. You can find a complete list of valid headers on MDN’s HTTP Headers Reference . The "body" of a request contains any information you want to send to the server and is normally transmitted in the HTTP request's body by sending a single JSON-encoded data string . This information is usually the data you'd like to create a new resource with (with a POST request) or the modified value of a resource you'd like to update (with a PUT or PATCH request).  Now that we know the parts of an HTTP request, let’s take a look at what is returned in an HTTP response: the status code and the body data. Responses always include an HTTP status code in the response header. These status codes are numbers that indicate whether a request was successfully completed and range from the 100s to the 500s. Similar to HTTP requests, responses usually return body data in the form of JSON . To wrap it all up, let’s take a look at a real-world example with the Spotify API. Spotify’s Web API, which has a base URL of https://api.spotify.com/v1 , has an endpoint that lets you get a playlist by its ID . If you take a look at the docs , you'll see that the HTTP request’s endpoint ( https://api.spotify.com/v1/playlists/{playlist_id} ) requires a GET   HTTP method and must have a valid Authorization header . It also requires a path parameter of the playlist’s ID. So if you send a  GET request to https://api.spotify.com/v1/playlists/59ZbFPES4DQwEjBpWHzrtC , the API's response will include body data that look like this: This JSON includes things like the playlist’s number of followers, the URL of the cover image, the playlist’s name, and much more. Now that you have a solid understanding of REST APIs, try interacting with one yourself! Be sure to check out our new course being released soon, Build a Spotify Connected App , where we apply these concepts to build a real-world, full stack web app!

Thumbnail Image of Tutorial 5 Minute Intro to REST APIs

Building a Simple RESTful API with Go and chi

The Go programming language is designed to address the types of software infrastructure issues Google faced back in late 2007. At this time, Google predominantly built their infrastructure using the programming languages C++, Java and Python. With a large codebase and having to adapt to rapid technological changes in both computing and key infrastructure components (e.g., multi-core processors, computer networks and clusters), Google found it difficult to remain productive within this environment using these languages. Not only does Go's design focus on improving the productivity of developers/engineers, but Go's design incorporates the best features of C++, Java and Python into a single statically-typed, compiled, high-performance language: Using Go and a lightweight router library, such as chi , writing and launching a simple RESTful API service requires little time and effort, even if you have no experience with Go. chi 's compatibility with the Go standard library package net/http , optional subpackages (middleware, render and docgen) and consistent API allows you to compose mantainable, modular services that run fast. Plus, these services can be deployed to and thrive in a production environment . If you have previously built RESTful APIs using Node.js and a minimal web application framework, such as Express.js , then you will find this to be quite similar! Below, I'm going to show you: To install Go, visit the official Go downloads page and follow the instructions. If you want your machine to support multiple versions of Go, then I recommend installing GVM (Go Version Manager) . Note : This installation walkthrough will be for Mac OS X systems. Run the following command to install GVM to your machine: Either... A.) Close the current terminal window and open a new terminal window. Or... B.) Run the source command mentioned in the output to make the gvm executable available to the current terminal window. Run the following command to install the latest stable version of Go (as of 02/21, v1.16): Notice how the installation fails. The following error message is printed within the output: If we check the contents of the log file /Users/kenchan/.gvm/logs/go-go1.16-compile.log , then the actual cause of the failure will be shown: Because the go executable could not be found, and GVM assumes that this go executable should be Go v1.4, let's install Go v1.4 from binary: Apparently, there is an known issue with installing Go v1.4 on certain versions of Mac OS X. Instead, let's install Go v1.7.1 from binary: Then, set the go executable to Go v1.7.1: Set the environment variable $GOROOT_BOOTSTRAP to the root of this Go installation to build the new Go toolchain, which will provide the necessary tools to compile ( build ), format ( fmt ), run ( run ) source code, download and install packages/dependencies ( get ), etc.: Finally, let's install the latest stable version of Go and set the go executable to it: Note : The --default option sets this version of Go as the default version. Whenever you open a new terminal window and execute go version , this default version will be printed. Create a new project directory named "go-chi-restful-api": This RESTful API service will offer the following endpoints for accessing/manipulating "posts" resources: A post represents an online published piece of writing. It consists of a title, content, an ID and an ID of the user who authored the post: These endpoints will interface directly with JSONPlaceholder , a fake API for testing with dummy data. For example, when it receives a GET /posts request from a user, our Go RESTful API will check for this route and execute the route handler mapped to it. This route handler will send a request to https://jsonplaceholder.typicode.com/posts and pipe the response of that request back to the user. This project will be comprised of two Go files: Create these files within the root of the project directory: ( main.go ) A Go source file begins with a package clause. All source files within the same folder should have the same package name. main happens to be a special package name that declares the package outputs an executable rather than a library and has a main function defined within it. This main function is executed when we run the Go program. This program imports three standard library packages and one third-party package: Inside of the main function... ( posts.go ) This source file contains the sub-router for the /posts route and its sub-routes ( /posts/{id} ). Here, we import three standard library packages and one third-party package: An empty struct postsResources is defined to namespace all functionality related to "posts" resources. func (rs postsResource) Routes() chi.Router defines the Routes method on the struct postsResource . This method returns an instance of the chi router that handles the /posts route and its sub-routes. Recall previously how we attached this sub-router to the parent router in main.go : Note : A struct is a typed collection of fields. In this Routes function, several endpoints for /posts and its sub-routes are defined on this sub-router. Each method call on the r sub-router instance corresponds to a single endpoint: Along with the Routes function, each of these request handler functions is also defined on the struct postsResource . Let's explore the body of a request handler, List , to understand how request handlers work. When the user sends a GET request to /posts , the request handler for this endpoint sends a GET request to https://jsonplaceholder.typicode.com/posts via the http.Get method to fetch a list of posts. If an error is encountered while fetching this list of posts ( err is not nil ), then the http.Error method replies to the original request with the err object's message and a 500 status code ( http.StatusInternalServerError ). If the list is fetched successfully, then close the body of this response ( resp ) to avoid a resource leak. Set the "Content-Type" header of the response ( w , the one to send back to the user) to "application/json" since the posts data is in a JSON format. To extract the list of posts from resp , copy resp.Body to the w buffer with io.Copy , which uses a fixed 32 kB buffer to copy chunks of up to 32 kB at a time. Then, send this response with the retrieved posts back to the user. Once again, if an error is encountered, then reply to the original request with an error message and a 500 status code. Note : _ is commonly used to denote an unused variable. It serves as a placeholder. When sending a POST/PUT request to the RESTful API service, the body of this request can be accessed via r.Body . When the user sends a GET request to /posts/1 , the router must first pass the request through the PostCtx middleware handler. This middleware handler... In a request handler, values from the request's Context can be accessed by the value's corresponding key. So to get the URL parameter we extracted in the previous step and set as a Context value with the key id , call r.Context().Value("id") . Because both keys and values are of type interface{} in Context , cast this URL parameter value as a string . The http package provides shortcut methods for sending GET and POST requests via the Get and Post methods respectively. However, for PUT and DELETE requests, use the newRequest method to create these requests. You must explicitly pass the HTTP method to newRequest and manually add request headers. client.Do sends the HTTP request created by newRequest and returns an HTTP response. Once again, if an error is encountered, then reply to the original request with an error message and a 500 status code. We could have used io.ReadAll to extract the response body, like so... However, io.ReadAll is inefficient compared to io.Copy because it loads the entirety of the response body into memory. Therefore, if the service must handle a lot of users simultaneously, and the size of resp.Body is large (i.e. contents of a file), then it may run out of available memory and eventually crash. To run install RESTful API service, first install all required third-party dependencies. In this case, there is only one third-party dependency to install: github.com/go-chi/chi . Let's add the project's code to its own module using the following command: If you have previously worked with Node.js, then you can think of go.mod as Go's package.json . By having the project's code in its own module, the project's dependencies can now be tracked and managed. Run the following command to install the project's dependencies and generate a go.sum file that contains checksums of the modules that this project depends on: These checksums are used by Go to verify the integrity of the downloaded modules. If you have previously worked with Node.js, then you can think of go.mod as Go's package.json and go.sum as Go's package-lock.json . Run the following command to run the command: If you would like to run the service on a different port, then set the environment variable PORT to a different port number: Test the service by sending a POST request to /posts : It works! Try sending requests to the other endpoints. chi offers a lot of useful, pre-defined middleware handlers via its optional middleware package. Visit this link for a list of these middleware handlers. One such middleware handler is Logger , which prints on every incoming request: Let's import the github.com/go-chi/chi/middleware package and add the Logger middleware to main.go : ( main.go ) In a separate terminal tab/window, send the same POST request to /posts : Information about this request is logged to the terminal. Click here for a final version of the RESTful API. Try adding more routes to this RESTful API! JSONPlaceholder provides five other resources (comments, albums, photos, todos and users) that you can create endpoints for.

Thumbnail Image of Tutorial Building a Simple RESTful API with Go and chi

Testing a Go and chi RESTful API - Route Handlers (Part 1)

Testing plays a fundamental role in the development of quality software. Shipping and deploying software with undetected bugs and regressions opens up a can of terrible consequences such as losing the trust of end users or costing the business time and resources. In a large collaborative setting, having developers manually test each and every feature and user flow for bugs and regressions wastes valuable time that can be put towards improving other aspects of the software. As the codebase and team grows, this approach will not scale. By writing unit/integration/end-to-end tests, identifying and catching bugs and regressions throughout an entire codebase becomes a painless, automatable task that can easily be integrated into any continuous integration pipeline. Unlike most other languages, the Go programming language provides a built-in, standard library package for testing: testing . The testing package offers many utilities for automating the testing of Go source files. To write a test in Go, define a function with a name prefixed with Test (followed by a capitalized segment of text) and accepts an argument of struct type T , which contains methods for failing and skipping tests, running multiple tests in parallel, formatting test logs, etc. Example : This test checks whether the Sum function correctly calculates the sum of two integer numbers. If the sum does not match the expected value, then the test logs an error message and marks itself as having failed. Try it out in the Go Playground here . Below, I'm going to show you: Clone a copy of the Go and chi RESTful API from GitHub to your machine: This RESTful API specifies five endpoints for performing operations on posts: If you would like to learn how to build this RESTful API, then please visit this blog post . In the testless branch's version of the RESTful API, the posts.go file has been moved to a routes subdirectory, and the route handlers within this file have been refactored into a routes package to allow the testing of packages independent of the main package. Run the following command to install the project's dependencies: Note : If you run into installation issues, then verify that the version of Go running on your machine is v1.16 . To get started, let's create a posts_test.go file within the routes subdirectory. This file will contain tests for each of the route handlers within the posts.go file. Inside of posts.go , each endpoint is defined on the chi router via a corresponding routing method named as an HTTP method. To register the GET /posts endpoint on this router, call the .Get method with the route / (in main.go , this posts sub-router is attached to the main router along the /posts route). ( routes/posts.go ) rs.List ( rs refers to the PostsResource{} struct) is a route handler method defined on the PostsResource{} struct. It retrieves a list of posts from the JSONPlaceholder API: ( routes/posts.go ) Let's write a unit test , which tests a single unit of code (commonly a function), for the PostsResource{}.List route handler function. Start off with a simple failing test that will immediately fail and print the message "Not yet implemented." to the terminal: ( routes/posts_test.go ) To test all packages within the current working directory recursively... To test the route handler for GET /posts : Let's combine these code snippets together: ( routes/posts_test.go ) Run the test: Congrats! The route handler test passes! Notice how the TestGetPostsHandler takes approximately half a second to run due to the network request the PostsResource{}.List route handler sent to the JSONPlaceholder API. If the JSONPlaceholder API experiences heavy traffic or any server outages/downtime, then the network request may either take too long to send back a response or completely time out. Because our tests rely on the status of a third-party service, which we have no control over, our tests take much longer to finish running. Let's work on eliminating this unreliability factor from TestGetPostsHandler . PostsResource{}.List calls the GetPosts function, which sends this network request and pipes the response back into PostsResource{}.List if there was no network request error encountered. ( routes/posts.go ) Since the function responsible for sending the network request ( GetPosts ) is a package-scoped variable within the routes package, this function can be replaced with a mock function , which replaces the actual implementation of a function with one that simulates its behavior. Particularly, the network request will be simulated. As long as the mock function has the same function signature as the original function, calling the route handler in a test will remain the same. Inside of posts_test.go , add a mock function for GetPosts : ( posts_test.go ) This mock function creates some dummy data ( mockedPosts , which is a list containing one post), encodes this data as JSON via json.Marshal and returns a minimal HTTP response with a status code and body. These fields adhere to the http package's Response struct. At the top of the TestGetPostsHandler test, set the GetPosts package-scoped variable to this mock function and change the expectedTotal to 1 : Run the test: Wow! The mock allows our test to run much faster. Click here for a final version of the route handler unit test. Try writing tests for the other route handlers.

Thumbnail Image of Tutorial Testing a Go and chi RESTful API - Route Handlers (Part 1)

Building a GraphQL Application with Vue 3 and Apollo

RESTful APIs adhere to a reliable architectural standard for transferring data statelessly over the HTTP protocol. Every endpoint of an API semantically describes how a resource should be created ( POST ), read ( GET ), updated ( PUT / PATCH ), deleted ( DELETE ), etc. Large, data-driven applications consume data from multiple third-party/in-house sources, and each one exposes a unique set of endpoints to manage different resources. Adapting these applications to support a wide range of platforms and device sizes (commonly mobile, desktop and web) may present several problems: Using Facebook's GraphQL query language, the client specifies its exact data requirements to the server via a single endpoint. Establishing a schema (written with the syntax of the GraphQL Schema Definition Language) creates a contract between the client and server that defines what data can be read from and written to the data graph by the client. This data graph centralizes all of the APIs consumed by your application by mapping each field to a resolver that populates it with a value retrieved from an endpoint of one of these APIs, a database, etc. A client can fetch data from a GraphQL server via plain HTTP and then manually update the UI accordingly. However, GraphQL clients such as Apollo Client abstract away the low-level implementation details of these features underneath a declarative API. Built by the Apollo GraphQL team, Apollo Client is an open-source GraphQL client that provides a lot of out-of-the-box functionality for communicating with a GraphQL server: To integrate Apollo Client into an application using another JavaScript library/framework besides React, which Apollo Client already has built-in support for, there exists view integration libraries within the Apollo ecosystem that provide bindings for Vue , Svelte , Angular , Ember and Web Components . The Vue Apollo library integrates Apollo Client into a Vue application. Different versions of Vue Apollo are compatible with different versions of Vue: Although Vue Apollo v4 is still in active development (alpha phase), it offers support for Vue 3's Composition API , which collocates the methods corresponding to component options ( watch , computed , etc.) and lifecycle hook registrations ( onMounted , onUnmounted , etc.) within a single component option, setup . Using Vue Apollo v4 methods, such as useQuery and useMutation , the data requirements are also placed within the setup method. This approach makes it much easier to reason about a component's code compared to the Vue Apollo Options API approach, which places the data requirements within an apollo component option (independent of the other code placed within the remaining component options). Below, I'm going to show you: Using Vue 3's Composition API and the Vue Apollo (v4) library, we will be building the following GitHub search client: To start, download this project from GitHub: This repository is based on a custom Vue CLI project template that runs Vue 3 and includes support for TypeScript, ESLint and Prettier. If you want to learn how to manually set up the base structure of this project, then proceed to the next section (" Installation "). Otherwise, you may skip the " Installation " section, download the already prepared project structure and proceed directly to the " GitHub GraphQL API " section. To generate a new Vue CLI project, run the following command in the terminal: When prompted with "Please pick a preset," select the "Manually select features" option: This project will support TypeScript. Press "Space" to select "TypeScript." When prompted with "Choose a version of Vue.js that you want to start the project with," select the "3.x (Preview)" option: Vue components will not be written with the class syntax. The Class API was officially dropped . This project will use Babel alongside TypeScript. For linting and code formatting, select the "ESLint + Prettier" option: Anytime changes to a file are saved, run the linter. For this project, let's place the Babel, ESLint, etc. configurations within their own dedicated files to avoid increasing the size of package.json . These answers are only for this project. In the future, you may want to try out different sets of project configurations to determine what specific tools make you more productive. To integrate type definitions from the schema of GitHub's GraphQL API , install @octokit/graphql-schema : Several type definitions are assigned nullable types , which will cause ESLint to raise the following error within your IDE. Inside of the .eslintrc.js file, turn off the rule @typescript-eslint/no-non-null-assertion . ( .eslintrc.js ) In 2017, GitHub publicly released its GraphQL API . GitHub's GraphQL API exposes a public schema for interacting with GitHub itself, whether fetching commit data or starring a repository, all accessible from a single endpoint. To send requests to GitHub's GraphQL API, generate an access token. This access token must be set to each request's Authorization header. When setting permissions for the access token, enable repository privileges. Create a .env file at the root of the project directory. Copy the 40 character-long access token to your clipboard. Set the environment variable VUE_APP_GITHUB_ACCESS_TOKEN to this access token. ( .env ) Note : Environment variables prefixed with VUE_APP_ can be accessed via process.env within Vue applications. Without this prefix, environment variables are undefined . First, install graphql , @apollo/client and @vue/apollo-composable as dependencies: To rapidly style the UI interface, we will be using the Tailwind CSS framework. Install tailwindcss , postcss and autoprefixer as dependencies: Then, create a minimal Tailwind configuration file ( tailwind.config.js ) at the root of the project directory. Note : The -p flag creates a minimal PostCSS configuration file ( postcss.config.js ) at the root of the project directory, alongside the generated tailwind.config.js . Inside of tailwind.config.js , set the purge option to a list of filenames/globs for PurgeCSS to analyze and remove unused CSS. ( tailwind.config.js ) Inside of public/index.html , add these two CSS classes to the <body /> element: ( public/index.html ) When you run the application, you will encounter the following error: Although the latest version of the tailwindcss PostCSS plugin (v2) is compatible with latest version PostCSS (v8), other tools within the PostCSS ecosystem may not yet be compatible with this version of PostCSS. To resolve this error, uninstall tailwindcss , postcss and autoprefixer , and then reinstall these dependencies with the PostCSS (v7) compatibility build. Inside of main.ts (the entry point of the Vue 3 application), create an ApolloClient instance. Let's pass an object containing configuration options to the Apollo Client: For this application, we will define two links: To inject the Apollo Client into the application and allow child components to access the Apollo Client, call the provide method within the createApp 's setup method to "provide" this client to the application and its children components. Since this application only interacts with a single GraphQL API, set this client as the default client. Putting it altogether... ( main.ts ) Our application requires three child components: By default, the reactive searchOptions object, which represents the arguments passed to the GitHub GraphQL API's search query, is dynamically assigned to the prop search-options of the <RepositoryList /> component. Any changes to searchOptions , particularly to query , which corresponds to the value of the search bar's input, will cause the <RepositoryList /> component to retrieve a new list of repositories. The value of query is changed whenever the search event is emitted from the <SearchBar /> component, which occurs on changes to the value of its input. ( src/App.vue ) Typing a query emits a "search" event with the current query and triggers the search function in the <App /> component. This search function sets the value of the query field in the reactive searchOptions object. Debounce the handleInputChange event handler to avoid sending the search event on every single input change. ( src/components/SearchBar.vue ) When an event is fired, this debounce function starts a timer and waits for a specific time period to elapse before calling its corresponding event handler. If another event is fired during this time period, then the previous event is ignored. The timer resets and must wait for the specific time period (now reset) to elapse before calling the new event's corresponding event handler. This debounce function invokes the event handler on the trailing edge of the timeout. ( src/utils.ts ) Store the queries and mutations within a single file. This application requires only one query and two mutations: If you decide to add more queries/mutations that return a repository/repositories, and you request for the same repository fields for those queries/mutations, then use the repo fragment to keep your code DRY. ( src/graphql/documents.ts ) Inside of the <RepositoryList /> component, fetch a list of repositories based on the searchOptions passed from the <App /> parent component. To fetch this list of repositories, the component executes the composition function useQuery , which accepts a GraphQL document ( SEARCH_REPOS ) as the first argument and query arguments ( searchOptions ) as the second argument. This function is compatible with the setup function of Vue 3's Composition API. useQuery returns an object that contains several Ref values: Sometimes, a query may return multiple top-level objects. To pick a single object from the result object returned by useQuery , use the useResult composition function. Instead of referencing the repositories from the result object as result.search.edges in the component's template, it can just be referenced as repositories . Plus, the default value assigned to repositories is the second argument passed to useResult (in this case, an empty array). ( src/components/RepositoryList.vue ) Inside of the <Repository /> component, there is a button for starring/unstarring a repository, depending on whether or not you have starred the repository previously. If you have not yet starred the repository, then clicking the button will star the repository, and vice-versa. The event handler calls either the unstarRepo or starRepo functions to unstar or star a repository respectively. Each of these functions execute the composition function useMutation , which accepts a GraphQL document ( ADD_STAR or REMOVE_STAR ) as the first argument and options (an object containing mutation arguments via the variables property, etc.) as the second argument. Similar to useQuery , this function is compatible with the setup function of Vue 3's Composition API. When a repository is starred/unstarred, we must update the cache to reflect this mutation. To understand why this is important, let's walkthrough an example. Imagine you typed the query "facebook" into the search bar's input. This will fetch all repositories relevant to "facebook" from GitHub's GraphQL API. Suppose you have already starred the facebook/react repository, and you decide to unstar it. After you unstar it, you decide to type the query "google" into the search bar's input. This will fetch all repositories relevant to "google" from GitHub's GraphQL API. If you again type the query "facebook" into the search bar's input, then this will fetch all repositories relevant to "facebook" from the Apollo Client's cache . What was cached previously for this query was a list of repositories relevant to "facebook," including the facebook/react repository. However, this repository was cached when it was still starred. Therefore, we must modify this repository in the cache to reflect that it was recently unstarred. To update the cache, set the update property in the options object to a function that provides an instance of the cache and the data returned from a mutation. This function will call the overrideMutationStarCache , which will read the already cached data (via the cache 's readQuery method) and write the result of the mutation to the appropriate repository entity (via the cache 's writeQuery method). Don't forget to also increment/decrement the stargazers count! Putting it altogether... ( src/components/Repository.vue ) Run the application locally: Visit localhost:8080 in a browser to interact with the application. In this blog post, we only explored a very small subset of the GitHub GraphQL API. Try experimenting with other aspects of the public schema of the GitHub GraphQL API. For a more difficult challenge, try connecting an existing Vue 3 application to a custom GraphQL server. If you want to learn more about Vue 3, then check out Fullstack Vue :

Thumbnail Image of Tutorial Building a GraphQL Application with Vue 3 and Apollo

A Complete Code Tutorial To Working With APIs In Flask

In this post, I want to show you how to quickly put together a complete REST API using Flask. As you might know, Flask is a perfect fit for the job! Our example creates a movies API but you can follow this for any API you want to create! Here's what we'll cover: An API needs a data source, a URL scheme, and request methods that clients use to access resources. To keep things simple and focused on the API, we skip setting up a database and use an in-memory array to hold our movies. This allows us to focus on the API request methods. We set up our API code in a new Python file called app.py . We import these Flask helpers : Our first API route handles listing all movies. Here is the code that does this. We use a @app.route decorator to set the request URL. Our response returns a JSON formatted collection with the movies from our data store. When using a database like MySQL or MongoDB, this is where you would integrate database calls to fetch movie data. Here is how you implement retrieving a single movie. In this method, we match the movie based on the id in the URL. If one is found, we send it back, using jsonify to format it as JSON. When creating a new movie, a REST client sends the new movie's attributes in a JSON payload. It might look as shown in the image. Here is the method in our app that takes this payload and creates new movies. In this method, we first check if the user supplied a title for the new movie . If not, we abort the request. Note the 400 error code. Otherwise, we create a new movie with the supplied title , plot , and other attributes. We save it in the movies data store and return a JSON result with the saved movie . Our method here is also the most complex in this example. That's because it has to handle multiple moving parts. Let's break it down. We match the movie to update based on the id in the URL. If no match is found, we abort the request. We do the same if the user has not supplied a title or plot , or if the user has not supplied any valid JSON . Otherwise, we update the movie with the attributes supplied in request.json . If an attribute is not supplied in the request , we recycle its old value and use that. We then save the updated movie in our data store. The API is almost complete! Here's the code that handles delete requests. We match the movie based on the id in the URL. If a match is not found, we abort the request. Else, we remove the movie from our data store. We then return a JSON with the result . That completes our movies API! For more on Flask, check out our course Fullstack Flask where we've focused on building a whole, master-level SaaS app end to end.

Thumbnail Image of Tutorial A Complete Code Tutorial To Working With APIs In Flask