A quick introduction to Encore, a back-end framework for Go - Part 1

Encore is a new backend web framework written in Go. It allows you to quickly create backend services with all kind of tools (databases, dependency injection, authentication, middlewares, etc..). Let's take a quick look !

Encore logo

This article is based on the official documentation, this is the first part of a series of 2 posts

Quick start

Create your project

First of all, you must have the Go compiler installed on your system, I recommend you to use the latest version (1.19.1 at the time or writing this article).

Then you can install the encore CLI, by using brew (the recommended version), or you can also curl the installation script directly

curl -L https://encore.dev/install.sh | bash

Once you're done, verify that you can run encore in your terminal!

You can now create the project, simply run encore app create and select the Hello World template.

~/DEV/GO/Blog  encore app create
? App Name (lowercase letters, digits, and dashes) demo-blog
? Select app template: Hello World (Encore introduction)

Downloaded template hello-world.

Successfully created app demo-blog!
App ID:  demo-blog-n8w2
Web URL: https://app.encore.dev/demo-blog-n8w2

Useful commands:

    encore run
        Run your app locally

    encore test ./...
        Run tests

    git push encore
        Deploys your app

Get started now: cd demo-blog && encore run

Sign in ?

You may have noticed that you have to sign in to the encore website in order to complete your project creation, this is a mandatory step that can not be skipped. It is used for you to access the web dashboard, and facilitate the deployment if you want to use the cloud hosting.

Encore web dashboard

Start your app

Navigate to the newly created folder, then simply type encore run in your terminal.


  ✔ Building Encore application graph... Done!
  ✔ Analyzing service topology... Done!
  ✔ Generating boilerplate code... Done!
  ✔ Compiling application source code... Done!
  ✔ Starting Encore application... Done!

  Encore development server running!

  Your API is running at:     http://localhost:4000
  Development Dashboard URL:  http://localhost:37193/testencore-fy8i

10:09AM INF registered API endpoint endpoint=World path=/hello/:name service=hello
10:09AM INF listening for incoming HTTP requests

The Hello World endpoint

The Hello World template come with an Hello World endpoint, you can make an HTTP request to http://localhost:4000/hello/:name to get a response saying hello to the name you used at the :name parameter.

~/DEV/GO/Blog  curl -f http://localhost:4000/hello/Tristan
{
  "Message": "Hello, Tristan!"
}

Navigate to the hello/hello.go file, as you can see, it's mainly plain Go code, with a few things to notice.

If you look at the World function, you can notice a special comment just above :

//encore:api public path=/hello/:name
func World(ctx context.Context, name string) (*Response, error) {
    msg := "Hello, " + name + "!"
    return &Response{Message: msg}, nil
}

type Response struct {
    Message string
}

The //encore:api public path=/hello/:name comment tells the Encore compiler that this function is exposed to the public API, with a certain path, which can contain a parameter. This parameter can be automatically retrieved with function parameters.

The Response struct only represent the shape of the JSON response which will be returned to the user.

Note that you can make changes to the code, it will be auto-reloaded by Encore!

The development dashboard

Encore come with a nice looking dashboard to help you debug, test, and inspect you app. To access it, navigate to http://localhost:4000.

Encore Dashboard

The dashboard provide a tool for quickly testing your API endpoints (same as Swagger), some metrics regarding your last requests, an auto-generated API doc and a tool called Flow, that can be used to get an overview of all you app.

Encore API Docs in the Dashboard

Authentication

Let's add a simple authentication to our /hello route. To do so, you must replace the public access level by auth in the //encore:api comment.

//encore:api auth path=/hello/:name

If you save the file now, you will get a Encore compilation error:

Changes detected, recompiling...
hello/hello.go:20:1: cannot use "auth" access type, no auth handler is defined in the app

That's right, we have to define a function that will handle our authentication:

//encore:authhandler
func AuthHandler(ctx context.Context, token string) (auth.UID, error) {
    return "", &errs.Error{
        Code:    errs.Unauthenticated,
        Message: "invalid token",
    }
}

We tell encore that this function is used as an AuthHandler with the //encore:authhandler comment. This function will receive a Context and a token. The token come from the Authorization: Bearer <token> HTTP header.

Let's modify the function to integrate a very basic check:

//encore:authhandler
func AuthHandler(ctx context.Context, token string) (auth.UID, error) {
    if token != "secret" {
        return "", &errs.Error{
            Code:    errs.Unauthenticated,
            Message: "invalid token",
        }
    }

    return auth.UID("user"), nil
}

If the bearer token is secret, we authorize the user, simple as that!

Now, if you try to query the endpoint, you will get a 401 Unauthorized error:

~/DEV/GO/Blog/demo-blog master ❯ curl http://localhost:4000/hello/Tristan
{
  "code": "unauthenticated",
  "message": "invalid auth param",
  "details": null
}

But if you pass the Authorization header:

~/DEV/GO/Blog/demo-blog master ❯ curl -H "Authorization: Bearer secret" http://localhost:4000/hello/Tristan
{
  "Message": "Hello, Tristan!"
}

And voila, you can of course use an external auth provider like Firebase, Supabase, or your custom JWT logic.