Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration of Ksql and Encore for REST API Development (tutorial) #1009

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/primitives/secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ In some cases, it can be useful to define a secret for a specific environment in
You can do so with `encore secret set --env <env-name> <secret-name>`. Secret values for specific environments
take precedence over values for environment types.

You can use content files, for secrets, imagine you need a certificate for create a database connection example cockroachdb you can set crt.

```sh
encore secrets set --type dev,local Certification < ~/.postgresql/root.crt
```

### Environment settings

Each secret can only have one secret value for each environment type. For example: If you have a secret value that's shared between `development`, `preview` and `local`, and you want to override the value for `local`, you must first edit the existing secret and remove `local` using the Secrets Manager in the [Cloud Dashboard](https://app.encore.dev). You can then add a new secret value for `local`. The end result should look something like the picture below.
Expand Down
211 changes: 211 additions & 0 deletions docs/tutorials/create-api-with-ksql.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
seotitle: Create a REST API with Ksql and Encore
seodesc: See how you can use Ksql in your Encore application.
title: Create a REST API with Ksql and Encore
---

[Ksql](https://github.com/VinGarcia/ksql) is a popular tool for managing database

Encore provides excellent support for using them together to easily manage database schemas and migrations.
When you use Ksql, Encore will automatically create a database for you and run your migrations.


## Setting up Ksql
First you need to install Ksql in your machine, you can follow the instructions in the [Ksql](https://github.com/VinGarcia/ksql) repository.

Then, in the service that you want to use Ksql for, add the `*ksql.DB` as a dependency in your service struct (create a service struct if you don't already have one).

```sh
go get github.com/VinGarcia/ksql
go get github.com/vingarcia/ksql/adapters/kpostgres

```

## Create a pkg with the ksql connection

When use ksql you need use tag in your struct, see the example below

```go
//contracts.go
package ksqldb

import "time"

type User struct {
ID int64 `json:"id" ksql:"id"`
UserName string `json:"name" ksql:"username"`
Password string `json:"password" ksql:"password"`
Email string `json:"email" ksql:"email"`
CreatedAt time.Time `json:"created_at" ksql:"created_at"`
}


```

Now create the connection with ksql in your pkg

```go
//database.go
package ksqldb

import (
"encore.dev/storage/sqldb"
"github.com/vingarcia/ksql"
"github.com/vingarcia/ksql/adapters/kpostgres"
"go4.org/syncutil"
)

var _ = sqldb.NewDatabase("orders", sqldb.DatabaseConfig{
Migrations: "./migrations",
})

// Get returns a database connection to the database.
// It is lazily created on first use.
func Get(orderdb *sqldb.Database) (ksql.DB, error) {
// Attempt to setup the database connection pool if it hasn't
// already been successfully setup.
err := once.Do(func() error {
var err error
db, err = setup(orderdb)
return err
})

return db, err
}

var (
// once is like sync.Once except it re-arms itself on failure
once syncutil.Once
// db is the database connection
db ksql.DB
)

// setup attempts to set up a database connection pool.
func setup(orderdb *sqldb.Database) (ksql.DB, error) {
return kpostgres.NewFromSQLDB(orderdb.Stdlib())
}
```

## Using the ksql connection in your service
```go
package users

import (
"context"

"encore.app/pkg/ksqldb"
"encore.dev/storage/sqldb"
"github.com/vingarcia/ksql"
)

var usersdb = sqldb.Named("orders")
var table = ksql.NewTable("users")

//encore:service
type Service struct {
db *ksql.DB
}

func initService() (*Service, error) {

db, err := ksqldb.Get(usersdb)

if err != nil {
return nil, err
}

return &Service{
db: &db,
}, nil
}

// SAve users
func (s *Service) Save(ctx context.Context, user ksqldb.User) (*ksqldb.User, error) {

err := s.db.Insert(ctx, table, &user)

if err != nil {
return nil, err
}

return &user, nil
}

// Get all userss
func (s *Service) GetAll(ctx context.Context) (*[]ksqldb.User, error) {

var users []ksqldb.User

err := s.db.Query(ctx, &users, "SELECT * FROM users")

if err != nil {
return nil, err
}

return &users, nil
}

```

Afer that you can use the service in your api

```go
package users

import (
"context"
"fmt"

"encore.app/pkg/ksqldb"
"encore.dev/beta/errs"
"encore.dev/rlog"
)

type Response struct {
Data string
}


//encore:api public method=POST path=/user
func (s *Service) CreateUser(ctx context.Context, request Request) (Response, error) {

if request.Name == "" || request.Email == "" || request.Password == "" {
return Response{}, &errs.Error{
Code: errs.InvalidArgument,
Message: "Name, email and password are required",
}
}

_, err := s.Save(ctx, ksqldb.User{
UserName: request.Name,
Email: request.Email,
Password: request.Password,
})

if err != nil {
rlog.Error(fmt.Sprintf("Error to save user %v", err))
return Response{}, &errs.Error{
Code: errs.InvalidArgument,
Message: "Error to save user",
}
}
return Response{
Data: "Usuario criado com sucesso",
}, nil
}

//encore:api public method=GET path=/users
func (s *Service) GetUsers(ctx context.Context) (*[]ksqldb.User, error) {

users, err := s.GetAll(ctx)

if err != nil {
return nil, &errs.Error{
Code: errs.InvalidArgument,
Message: "Error to get users",
}
}

return users, nil
}
```
12 changes: 12 additions & 0 deletions docs/tutorials/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,16 @@ Check out these tutorials to learn how to build applications with Encore and fin
</div>
</div>
</a>
<a className="block group relative no-brandient" href="/docs/tutorials/create-api-with-ksql">
<div className="absolute inset-0 bg-black dark:bg-white -z-10" />
<div className="min-h-full border border-black dark:border-white bg-white dark:bg-black transition-transform duration-100 ease-in-out group-active:-translate-x-2 group-active:-translate-y-2 group-hover:-translate-x-2 group-hover:-translate-y-2 relative">
<div className="flex-none">
<img className="width-100% noshadow" src="/assets/tutorials/ksql/cover.png" />
</div>
<div className="p-8 mobile:p-4">
<h3 className="body-small">Api with Ksql and Encore</h3>
<p className="mt-2">Create a fast api using ksql package with Encore</p>
</div>
</div>
</a>
</div>