在少于100行的GO(使用数据库)中设置免费且可生产的Web应用程序后端
#网络开发人员 #云 #go #backend

https://github.com/encoredev/example-meeting-notes

在本教程中,我们将在不到100行代码中使用Encore创建一个后端。后端将:

  • 将数据存储在云SQL数据库中
  • 向第三方服务拨打API
  • 部署到云中,公开可用(免费和生产)

Encore是一个后端开发平台,可帮助您很快在云中启动并在云中运行。这对于爱好项目和初创企业来说都是理想的选择,因为它可以抽象所有云基础架构废话,并带有免费的后端部署并通过Encore Cloud托管。 (如果您的产品取得了巨大的成功,您可以将Encore连接到AWS或GCP并在此处部署您的后端。)

我们将构建的示例应用程序是Markdown Meeting Notes应用程序,但是如果您有另一个想法(同样,少于100行代码),则替换细节很琐碎。

Demo version of the app

meeting notes app

要使用Encore开发,您需要Encore CLI。它编译您的代码并运行您的本地开发仪表板:

# Mac
$ brew install encoredev/tap/encore

# Win
$ iwr <https://encore.dev/install.ps1> | iex

# Linux
$ curl -L <https://encore.dev/install.sh> | bash

从会议记录示例中创建一个新应用。这将使您从本教程中描述的所有内容开始:

$ encore app create meeting-notes --example=github.com/encoredev/example-meeting-notes

您将被要求创建一个免费帐户。稍后,当我们使用Encore可以部署我们的应用时,这将需要。

在本地运行该项目之前,请确保已安装和运行Docker。 Encore需要Docker创建用于本地运行项目的数据库。另外,如果您想尝试照片搜索功能,则需要pexels.com/api/的API键(以下更多内容)

在本地运行后端:

$ cd you-app-name # replace with the app name you picked
$ encore run

您应该看到以下内容:

encore run

这意味着您的本地开发后端正在启动并运行! Encore负责为您的应用程序(包括数据库)设置所有必要的基础架构。 Encore还启动了本地开发仪表板,这是一种工具,可以帮助您在开发新功能时更快地移动。

encore dev dashboard

要启动前端,在另一个终端窗口中运行以下命令:

$ cd you-app-name/frontend
$ npm install
$ npm run dev

您现在可以在浏览器中打开http://localhost:5173/example-meeting-notes/ð¥

从SQL数据库存储和检索

让我们看一下后端代码。本质上只有三个有趣的文件,让我们从查看note.go开始。该文件包含两个端点和一个接口,所有标准的GO代码除了特定于Encore的几行。

Note类型代表我们的数据结构:

type Note struct {
    ID       string `json:"id"`
    Text     string `json:"text"`
    CoverURL string `json:"cover_url"`
}

每个音符都会具有ID(在前端上创建的uuid),Text(markdown文本内容)和CoverURL(背景图像URL)。

SaveNote函数处理存储会议注:

//encore:api public method=POST path=/note
func SaveNote(ctx context.Context, note *Note) (*Note, error) {
    // Save the note to the database.
    // If the note already exists (i.e. CONFLICT), we update the notes text and the cover URL.
    _, err := sqldb.Exec(ctx, `
        INSERT INTO note (id, text, cover_url) VALUES ($1, $2, $3)
        ON CONFLICT (id) DO UPDATE SET text=$2, cover_url=$3
    `, note.ID, note.Text, note.CoverURL)

    // If there was an error saving to the database, then we return that error.
    if err != nil {
        return nil, err
    }

    // Otherwise, we return the note to indicate that the save was successful.
    return note, nil
}

上面的评论告诉Encore,这是一个公共端点,应该可以通过/note上的帖子来达到。该功能的第二个参数(Note)是邮局,该功能返回Noteerrornil错误是指200响应)。

GetNote函数照顾从我们的数据库中获取id的会议注释:

//encore:api public method=GET path=/note/:id
func GetNote(ctx context.Context, id string) (*Note, error) {
    note := &Note{ID: id}

    // We use the note ID to query the database for the note's text and cover URL.
    err := sqldb.QueryRow(ctx, `
        SELECT text, cover_url FROM note
        WHERE id = $1
    `, id).Scan(&note.Text, &note.CoverURL)

    // If the note doesn't exist, we return an error.
    if err != nil {
        return nil, err
    }

    // Otherwise, we return the note.
    return note, nil
}

在这里,我们有一个带有动态路径参数的公共端点,这是会议注释的id。在这种情况下,第二个参数是动态路径参数,该端点的请求看起来像/note/123-abc,其中id将设置为123-abc

SaveNoteGetNote使用了名为note的SQL数据库表,让我们看一下如何定义该表。

定义SQL数据库

要使用Encore创建一个SQL数据库,我们首先创建一个名为migrations的文件夹,在该文件夹中,一个名为1_create_tables.up.sql的迁移文件。该文件名很重要(必须看起来像1_.up.sql)。我们的迁移文件只有五行长,看起来像这样:

CREATE TABLE note (
    id TEXT PRIMARY KEY,
    text TEXT,
    cover_url TEXT
);

识别此文件时,Encore将创建一个带有三列idtextcover_urlnote表。 id是主要键,用于识别特定的会议笔记。

向第三方API提出请求

让我们看一下如何使用Encore端点来代理第三方服务的代理请求(在此示例中,Photo Service pexels.com,但对于任何其他第三方API,这个想法都是相同的)。

文件pexels.go只有一个端点,SearchPhoto

//encore:api public method=GET path=/images/:query
func SearchPhoto(ctx context.Context, query string) (*SearchResponse, error) {
    // Create a new http client to proxy the request to the Pexels API.
    URL := "<https://api.pexels.com/v1/search?query=>" + query
    client := &http.Client{}
    req, _ := http.NewRequest("GET", URL, nil)

    // Add authorization header to the req with the API key.
    req.Header.Set("Authorization", secrets.PexelsApiKey)

    // Make the request, and close the response body when we're done.
    res, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer res.Body.Close()

    if res.StatusCode >= 400 {
        return nil, fmt.Errorf("Pexels API error: %s", res.Status)
    }

    // Decode the data into the searchResponse struct.
    var searchResponse *SearchResponse
    err = json.NewDecoder(res.Body).Decode(&searchResponse)
    if err != nil {
        return nil, err
    }

    return searchResponse, nil
}

再次具有动态路径参数的获取端点,这次代表我们要发送到PEXELS API的查询文本。

我们用来解码PEXELS API的响应的类型看起来像这样:

type SearchResponse struct {
    Photos []struct {
        Id  int `json:"id"`
        Src struct {
            Medium    string `json:"medium"`
            Landscape string `json:"landscape"`
        } `json:"src"`
        Alt string `json:"alt"`
    } `json:"photos"`
}

我们从Pexels获得了更多数据,但是在这里,我们只选择要传播到前端的字段。

Pexels API需要一个API键,就像大多数开放的API一样。 API键是作为请求的标题添加的(从上面的SearchPhoto函数):

req.Header.Set("Authorization", secrets.PexelsApiKey)

在这里,我们本可以对API密钥进行硬编码,但这将使每个人都可以访问我们的存储库。相反,我们使用了Encore的内置secrets management。要设置此秘密,请在项目文件夹中运行以下命令,然后按照提示:

encore secret set --type dev,prod,local,pr PexelsApiKey

创建请求客户端

Encore能够生成前端request clients(打字稿或JavaScript)。这意味着您无需手动将请求/响应对象保持在前端的同步,大量节省时间。生成客户端运行:

$ encore gen client <APP_NAME> --output=./src/client.ts --env=<ENV_NAME>

您将要经常运行此命令(每当您对端点进行更改时),因此将其作为npm脚本是一个好主意:

{
...
"scripts": {
    ...
    "generate-client:staging": "encore gen client meeting-notes-8ami --output=./src/client.ts --env=staging",
    "generate-client:local": "encore gen client meeting-notes-8ami --output=./src/client.ts --env=local"
  },
}

之后,您准备在代码中使用请求客户端。这是调用GetNote端点的示例:

import Client, { Environment, Local } from "src/client.ts";

// Making request to locally running backend...
const client = new Client(Local);
// or to a specific deployed environment
const client = new Client(Environment("staging"));

// Calling APIs as typesafe functions 🌟
const response = await client.note.GetNote("note-uuid");
console.log(response.id);
console.log(response.cover_url);
console.log(response.text);

将后端部署到云

是部署时间!为了使您的后端部署在云中,您需要做的就是提交代码并将其推向encore遥控器:

$ git add -A .
$ git commit -m 'Initial commit'
$ git push encore

运行git push encore时,您将获得指向Encore Cloud Dashboard的链接,您可以在其中查看应用程序的部署,大约一分钟后,您将在云中运行一个后端

encore cloud dashboard

主持前端

可以将前端部署到任何静态站点托管平台。示例项目已预先配置,将前端部署到GitHub Pages。看一下.github/workflows/node.yml,以查看GitHub操作工作流程在新提交的仓库上触发的工作流程:

name: Build and Deploy

on: [push]

permissions:
  contents: write

jobs:
  build-and-deploy:
    concurrency: ci-${{ github.ref }}
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: frontend

    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v3

      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16.15.1'

      - name: Install and Build 🔧
        run: |
          npm install
          npm run build

      - name: Deploy 🚀
        uses: JamesIves/github-pages-deploy-action@v4.3.3
        with:
          branch: gh-pages
          folder: frontend/dist

有趣的部分是向下构建前端代码并利用github-pages-deploy-action步骤,以自动对gh-pages分支的汇编的前端代码自动进行新提交。

部署到github页面的步骤:

  1. 在Github上创建回购
  2. vite.config.js文件中,将base属性设置为repo的名称:
base: "/my-repo-name/",
  1. 将您的代码推向github并等待github操作工作流程完成。
  2. ug ags to ame,关于propaghy peacher aboly on per on per,ywyonally on enryally yakely yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yaly yacly yacly yaly yaly yaly yaly ..是贾特吗?

包起来

- 很棒!您现在在云中运行一个完整的应用程序!

您学会了如何使用Encore构建和部署GO后端,将数据存储在SQL数据库中,然后对外部服务进行API调用。

Encore可让您构建可准备生产的后端,而无需在设置真正的云基础架构方面的样板和手动工作。如果您想继续构建更高级的应用程序,我建议您查看其他Encore tutorials availableð¥