avatar

Đăng vào

HTML Reader với Golang và Lambda function

Tác giả

Go reader

Mục lục

Repository của hướng dẫn này có tại đây

Trong bài viết này, chúng ta sẽ xem xét cách triển khai bất kỳ hàm Golang nào lên AWS Lambda một cách siêu dễ dàng. Chúng ta có thể chạy hầu như tất cả các loại ứng dụng, back end service với zero administration (không cần quản lý)

Vậy thì chúng ta sẽ làm gì?

Macos reader

Chúng ta sẽ phát triển một html reader tương tự với reader mode trên các trình duyệt web hiện tại. Chọn ảnh hơi cay nhé ông bạn 🥲

Thiết kế

Hệ thống với yêu cầu đơn giản nên chúng ta cũng sẽ có diagram đơn giản. Flow:

  1. Người dùng truy cập vào html reader với params url là địa chỉ của trang muốn đọc
  2. Lambda function sẽ get html code, parse và format lại nội dung chính bằng thư viện go-readability1
  3. Trả HTML nội dung chính được xử lý tại Lambda fucntion

Go reader Diagram

Triển khai

SAM local

shell
sam init --name go-reader --runtime go1.x
shell
vi ~/.aws/credentials
~/.aws/credentials
[vntechies]
aws_access_key_id=******
aws_secret_access_key=******
  • Tạo template cho hệ thống sử dụng SAM
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  go-reader

  Sample SAM Template for go-reader

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 5

Resources:
  GoReaderFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: go-reader/
      Handler: handler
      Runtime: go1.x
      Architectures:
        - x86_64
      Events:
        CatchAll:
          Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /
            Method: GET
            ApiId: !Ref GoReaderHTTPApi

  GoReaderHTTPApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      CorsConfiguration:
        AllowOrigins:
          - "*"
        AllowHeaders:
          - "Content-Type"
          - "Access-Control-Allow-Origin"
          - "Access-Control-Allow-Headers"
        AllowMethods:
          - GET
          - OPTIONS

Outputs:
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  GoReaderAPI:
    Description: "API Gateway endpoint URL for Prod environment for First Function"
    Value: !Sub "https://${GoReaderHTTPApi}.execute-api.${AWS::Region}.amazonaws.com/"
  GoReaderFunction:
    Description: "First Lambda Function ARN"
    Value: !GetAtt GoReaderFunction.Arn
  GoReaderFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt GoReaderFunction.Arn
  • Một số lưu ý

    • Lambda function connect được với public Internet by default
    • AWS::Serverless::HttpApi sử dụng HTTP API thay vì REST API vì chỉ cần Regional access và không cần những tính năng của REST API -> giảm chi phí
    • AllowHeaders
      • Content-Type lambda function sẽ serve html code và trả về cho người dùng thông qua API gateway, API Gateway cần phải truyền headers này tới user, nếu không browser sẽ hiển thị response dưới dạng text thay vì html code.

Hàm Lambda cho GoReader

  • Sau khi lấy được nội dung chính của trang web qua url người dùng cung cấp, chúng ta sẽ format lại sử dụng thư viện bamboo css2
go-reader/main.go
package main

import (
	"errors"
	"time"

	readability "github.com/go-shiori/go-readability"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

var (
	ErrNoURL = errors.New("No URL provided")
)

func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
	url := request.QueryStringParameters["url"]

	if len(url) <= 0 {
		return events.APIGatewayProxyResponse{}, ErrNoURL
	}

	article, err := readability.FromURL(url, 30*time.Second)

	if err != nil {
		return events.APIGatewayProxyResponse{}, err
	}

	html := "<!DOCTYPE html><html><head><meta charset='utf-8'/><title>GO READER</title><meta name='viewport' content='width=device-width, initial-scale=1'/><link rel='stylesheet' href='https://unpkg.com/bamboo.css'/></head><body><h2 id='title'>" + article.Title + "</h2><h4>" + article.Excerpt + "</h4><p id='output'>" + article.Content + "</p></body></html>"
	return events.APIGatewayProxyResponse{
		StatusCode: 200,
		Headers: map[string]string{
			"Access-Control-Allow-Origin":  "*",
			"Access-Control-Allow-Headers": "origin,Accept,Authorization,Content-Type",
			"Content-Type":                 "text/html; charset=utf-8",
		},
		Body:            html,
		IsBase64Encoded: false,
	}, nil
}

func main() {
	lambda.Start(handler)
}
  • Cài đặt cách thư viện cần thiết trước khi đóng build và đóng gói hàm
shell
cd go-reader
go get github.com/go-shiori/go-readability

Test & Validate & Build & Deploy

shell
# test function bằng event mẫu từ APIGW
sam local invoke "GoReaderFunction" -e events/error_event.json
sam local invoke "GoReaderFunction" -e events/event.json

# validate SAM template
sam validate --profile vntechies --region ap-southeast-1

# build package
sam build

# deploy
sam deploy --guided --profile vntechies

Sản phẩm

Reader compare

Kết luận: Như 2 giọt nước 🤣

Với việc support nhiều ngôn ngữ và có thể nhanh chóng, dễ dàng triển khai một dịch vụ mới, Lambda là một lựa chọn tốt cho các stack công nghệ phát triển với Golang.

VNTechies Dev Blog

Kho tài nguyên mã nguồn mở với sứ mệnh đào tạo kiến thức, định hướng nghề nghiệp cho cộng đồng Cloud ☁️ DevOps 🚀

Facebook page

Tham gia group VNTechies - Cloud ☁️ / DevOps 🚀 nếu bạn muốn giao lưu với cộng đồng và cập nhật các thông tin mới nhất về Cloud và DevOps.

Discord banner

Anh chị em hãy follow/ủng hộ VNTechies để cập nhật những thông tin mới nhất về Cloud và DevOps nhé!

Footnotes

  1. https://github.com/go-shiori/go-readability

  2. https://github.com/rilwis/bamboo