|
1 | 1 | // Package backend allows a Go program to import a standard Go package
|
2 |
| -// instead of self-hosting the backend API. |
| 2 | +// instead of self-hosting the backend API in a separate web server. |
3 | 3 | //
|
4 | 4 | // You need to call the [Setup] function to initialize all services passing
|
5 | 5 | // a [github.com/staticbackendhq/core/config.AppConfig]. You may create
|
6 | 6 | // environment variables and load the config directly by confing.Load function.
|
7 | 7 | //
|
| 8 | +// // this sample uses the in-memory database provider built-in |
| 9 | +// // you can use PostgreSQL or MongoDB |
| 10 | +// cfg := config.AppConfig{ |
| 11 | +// AppEnv: "dev", |
| 12 | +// DataStore: "mem", |
| 13 | +// DatabaseURL: "mem", |
| 14 | +// LocalStorageURL: "http://localhost:8099", |
| 15 | +// } |
| 16 | +// backend.Setup(cfg) |
| 17 | +// |
8 | 18 | // The building blocks of [StaticBackend] are exported as variables and can be
|
9 | 19 | // used directly accessing their interface's functions. For instance
|
10 |
| -// to use the Volatilizer (cache and pub/sub) you'd use the [Cache] variable: |
| 20 | +// to use the [github.com/staticbackendhq/core/cache.Volatilizer] (cache and |
| 21 | +// pub/sub) you'd use the [Cache] variable: |
11 | 22 | //
|
12 | 23 | // if err := backend.Cache.Set("key", "value"); err != nil {
|
13 | 24 | // return err
|
14 | 25 | // }
|
15 | 26 | // val, err := backend.Cache.Get("key")
|
16 | 27 | //
|
17 | 28 | // The available services are as follow:
|
18 |
| -// 1. Cache: caching and pub/sub |
19 |
| -// 2. DB: a raw Persister instance (see below for when to use it) |
20 |
| -// 3. Filestore: raw blob storage |
21 |
| -// 4. Emailer: to send emails |
22 |
| -// 5. Config: the config that was passed to Setup |
23 |
| -// 6. Log: logger |
| 29 | +// - [Cache]: caching and pub/sub |
| 30 | +// - [DB]: a raw [github.com/staticbackendhq/core/database.Persister] instance (see below for when to use it) |
| 31 | +// - [Filestore]: raw blob storage |
| 32 | +// - [Emailer]: to send emails |
| 33 | +// - [Config]: the config that was passed to [Setup] |
| 34 | +// - [Log]: logger |
24 | 35 | //
|
25 | 36 | // You may see those services as raw building blocks that give you the most
|
26 |
| -// flexibility. For easy of use, this package wraps important / commonly used |
| 37 | +// flexibility to build on top. |
| 38 | +// |
| 39 | +// For easy of use, this package wraps important / commonly used |
27 | 40 | // functionalities into more developer friendly implementations.
|
28 | 41 | //
|
29 |
| -// For instance, the [Membership] function wants a model.DatabaseConfig and allows |
30 |
| -// the caller to create account and user as well as reseting password etc. |
| 42 | +// For instance, the [Membership] function wants a |
| 43 | +// [github.com/staticbackendhq/core/model.DatabaseConfig] and allows the caller |
| 44 | +// to create account and user as well as reseting password etc. |
31 | 45 | //
|
32 | 46 | // usr := backend.Membership(base)
|
33 | 47 | // sessionToken, user, err := usr.CreateAccountAndUser("[email protected]", "passwd", 100)
|
34 | 48 | //
|
35 | 49 | // To contrast, all of those can be done from your program by using the [DB]
|
36 | 50 | // ([github.com/staticbackendhq/core/database.Persister]) data store, but for
|
37 | 51 | // convenience this package offers easier / ready-made functions for common
|
38 |
| -// use-cases. Example: |
| 52 | +// use-cases. Example for database CRUD and querying: |
39 | 53 | //
|
40 | 54 | // tasks := backend.Collection[Task](auth, base, "tasks")
|
41 | 55 | // newTask, err := tasks.Create(Task{Name: "testing"})
|
|
44 | 58 | // input/output are properly typed, it's a generic type.
|
45 | 59 | //
|
46 | 60 | // [StaticBackend] makes your Go web application multi-tenant by default.
|
47 |
| -// For this reason you must supply a model.DatabaseConfig and sometimes a |
48 |
| -// model.Auth (user performing the actions) to the different parts of the system |
49 |
| -// so the data and security are applied to the right tenant, account and user. |
| 61 | +// For this reason you must supply a |
| 62 | +// [github.com/staticbackendhq/core/model.DatabaseConfig] and (database) and |
| 63 | +// sometimes a [github.com/staticbackendhq/core/model.Auth] (user performing |
| 64 | +// the actions) to the different parts of the system so the data and security |
| 65 | +// are applied to the right tenant, account and user. |
50 | 66 | //
|
51 | 67 | // You'd design your application around one or more tenants. Each tenant has
|
52 | 68 | // their own database. It's fine to have one tenant/database. In that case
|
53 | 69 | // you might create the tenant and its database and use the database ID in
|
54 | 70 | // an environment variable. From a middleware you might load the database from
|
55 | 71 | // this ID.
|
56 | 72 | //
|
| 73 | +// // if you'd want to use SB's middleware (it's not required) |
| 74 | +// // you use whatever you like for your web handlers and middleware. |
| 75 | +// // SB is a library not a framework. |
| 76 | +// func DetectTenant() middleware.Middleware { |
| 77 | +// return func(next http.Handler) http.Handler { |
| 78 | +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 79 | +// // check for presence of a public DB ID |
| 80 | +// // this can come from cookie, URL query param |
| 81 | +// key := r.Header.Get("DB-ID") |
| 82 | +// // for multi-tenant, DB ID can be from an env var |
| 83 | +// if len(key) == 0 { |
| 84 | +// key = os.Getenv("SINGLE_TENANT_DBID") |
| 85 | +// } |
| 86 | +// var curDB model.DatabaseConfig |
| 87 | +// if err := backend.Cache.GetTyped(key, &curDB); err != nil { |
| 88 | +// http.Error(w, err.Error(), http.StatusBadRequest) |
| 89 | +// return |
| 90 | +// } |
| 91 | +// curDB, err := backend.DB.FindDatabase(key) |
| 92 | +// // err != nil return HTTP 400 Bad request |
| 93 | +// err = backend.Cache.SetTyped(key, curDB) |
| 94 | +// // add the tenant's DB in context for the rest of |
| 95 | +// // your pipeline to have the proper DB. |
| 96 | +// ctx := r.Context() |
| 97 | +// ctx = context.WithValue(ctx, ContextBase, curDB) |
| 98 | +// next.ServeHTTP(w, r.WithContext(ctx))) |
| 99 | +// }) |
| 100 | +// } |
| 101 | +// } |
| 102 | +// |
| 103 | +// You'd create a similar middleware for adding the current user into the |
| 104 | +// request context. |
| 105 | +// |
57 | 106 | // If you ever decide to switch to a multi-tenant design, you'd already be all
|
58 | 107 | // set with this middleware, instead of getting the ID from the env variable,
|
59 | 108 | // you'd define how the user should provide their database ID.
|
|
0 commit comments