Serverless, cloud native, from the beginning of the year until now, several front-end public accounts and information accounts I follow are all pushing these things crazy. I heard about them at the end of last year, originally thought it was a variety of event conference organizations and cloud vendors selling tickets to devOPS in the whole new technology, but the heat is getting stronger and stronger, so I also want to try to get a heat

What is Serverless

Cloud Function + Object Storage + Cloud Database + API Gateway and more by Cloud Service Provider. Simply put, there is an open source framework called Serverless that consolidates these services from cloud vendors into a configuration file, eliminating all back-end operations. The benefits are obvious: flexible service, on-demand pricing, most of your operational problems covered by your cloud service provider and the ability of elementary school students to write websites.

Should we learn something about the front end and lay off the back end and operations?

Serverless, start!

Since Serverless graph is fast, then we naturally can’t go to the cloud service provider to manually set it up. Of course you can do the same, but my service goes live today and yours may have to wait until the day after tomorrow.

Serverless NPM package, NPM install -g Serverless, download! To start!

Any position, terminal input

$ serverless
Copy the code

The friendly wizard takes you step by step towards the Serverless Pit

Go to the project you just created and tap

$ sls deploy
Copy the code

Click the link given on the screen!

Hello World!
Copy the code

Cow force! Our back-end servers are set up! That’s easy!

Domestic user Serverless automatically uses Tencent Cloud

The above content is in www.serverless.com/framework/d… There are

Set a template, fast up fast

The following is done using AWS

Today I plan to make a credit card foreign exchange comparison tool, three steps to do:

  1. Crawl rate
  2. Save the current exchange rate (cloud function has no state)
  3. The front end calculates price comparisons

Ideal for beginner applications with Serverless

The code has been open source and online, welcome to review while reading

Visit whichcard.xingoxu.com/

Code address: github.com/xingoxu/whi…

Serverless this framework, can also use template to create projects, since the diagram is fast, find a ready-made template set in, fill a fill on the line is not more beautiful

Technology stack, choose nuxt.js, open SSR, plus programmable use, wonderful ah

Search the

serverless create --template-url https://github.com/tonyfromundefined/nuxt-serverless -n whichcard-abroad
Copy the code

After creating the project, let’s edit serverless.yml and add the non-relational database configuration

resources:
  Resources:
    CurrencyTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: ${env:DYANMODB_TABLE}
        AttributeDefinitions:
          - AttributeName: ${env:DYANMODB_PRIMARY_KEY}
            AttributeType: S
        KeySchema:
          - AttributeName: ${env:DYANMODB_PRIMARY_KEY}
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
Copy the code

The database needs to configure permissions. Give permissions to the user running lambda function, the user represented by the key you issued the first time you used Serverless, which is also added under serverless

provider:
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${env:DYANMODB_TABLE}"
Copy the code

Ok, our server is configured and we are ready to write the back end

Most of the templates we just used are already built, but there is no typescript support on the back end

Tsconfig. json copy it and rename it tsconfig-server.json

Configuration I will not stick over, you can refer to the above connection.

With typescript, I have to make it js before it can be read by lambda function, adding ts-loader to webpack.config.js.

Crawl rate

Let’s take VISA, whose exchange rate is posted on this page that day

We import Axios, import Cheerio, three clicks, five to two, jQuery shuttle, easy and happy, touch out his exchange rate

import axios from 'axios';
import cheerio from 'cheerio';
import { format } from 'date-fns';

const getVisaCurrency = async ({
  transCurr = "USD",
  billCurr = "JPY",
  date
}) => {
  const { data: htmlBody } = await axios.get<
    string> (`https://usa.visa.com/support/consumer/travel-support/exchange-rate-calculator.html`,
    {
      params: {
        amount: 1,
        fee: '0.0',
        utcConvertedDate: ' ',
        exchangedate: format(
          date,
          'MM/dd/yyyy'
        ),
        fromCurr: billCurr,
        toCurr: transCurr,
        submitButton:
          'Calculate exchange rate'}});const $ = cheerio.load(htmlBody);
  const $targetDOM = $(
    '.converted-amount-value'
  );
  const result = $targetDOM
    .eq($targetDOM.length - 2)
    .text()
    .match(/^\d+\.\d+/)! [0];

  return result;
};

export { getVisaCurrency };
Copy the code

In 40 lines of code, we solved the battle

Exchange rate on the day of preservation

Since you pay on demand, it’s impossible for cloud vendors to give you resources when you’re idle, so it makes sense that cloud functions are stateless

Although we can capture the exchange rate in real time for each request, this obviously affects the opening speed and user experience too much.

And if the upstream is found, the other party directly to aws a whole section of IP to the closure of the matter is not unknown

Even when it comes to grabbing public data, it’s better to do it quietly.

Import aws- SDK directly and write save utility functions and query utility functions in a few lines of code

The source code

import { DynamoDB } from 'aws-sdk';
import { format } from 'date-fns';

const DATE_FORMAT = 'yyyy-MM-dd';
const DYANMODB_TABLE: string = "currencyTable";
const DYANMODB_PRIMARY_KEY: string = "currency";

const dynamoDBClient = new DynamoDB({
  region: process.env.DYANMODB_REGION
});

const queryFromCache = async (
  date: Date) :Promise<DBCurrencyObject | undefined> = > {const {
    Count,
    Items
  } = await dynamoDBClient
    .query({
      TableName: DYANMODB_TABLE,
      KeyConditionExpression: `#key=:dt`,
      ExpressionAttributeNames: {
        '#key': DYANMODB_PRIMARY_KEY
      },
      ExpressionAttributeValues: {
        ':dt': {
          S: format(date, DATE_FORMAT)
        }
      }
    })
    .promise();
  if (Count && Count == 1)
    returnDyanmodbResultAdapter( Items! [0])as DBCurrencyObject;
  return undefined;
};

const storeResult = async ({
  date,
  result,
  billCurr,
  transCurr,
  brand
}): Promise<void> = > {let cacheResult = await queryFromCache(
    date
  );
  if(! cacheResult) cacheResult = { date: format(date, DATE_FORMAT) };if(! cacheResult[brand]) cacheResult[brand] = {};if(! cacheResult[brand]! [transCurr]) cacheResult[brand]! [transCurr] = {}; cacheResult[brand]! [transCurr]! [ billCurr ] = result;await dynamoDBClient
    .updateItem({
      Key: {
        [DYANMODB_PRIMARY_KEY]: {
          S: format(date, DATE_FORMAT)
        }
      },
      TableName: DYANMODB_TABLE,
      UpdateExpression: `set ${brand}= :${brand}`,
      ExpressionAttributeValues: {
        [` :${brand}`]: {
          M: DyanmodbRequestAdapter(
            cacheResult[brand]!
          )
        }
      }
    })
    .promise();
};

export { queryFromCache, storeResult };
Copy the code

DyanmodbRequestAdapter and DyanmodbResultAdapter are designed to solve the dyanmodb storage in accordance with his SDK recursion key (plus type), in addition, here is too long to omit some type definitions, you can view in the source code

At the same time, let’s not forget that new requests may occur during fetching/storing, so we’ll write a utility class to wrap up the fetching function

export function asyncOnce< T extends (... args: any) => Promise<any> >( func: ( ... args: Parameters<T> ) => ReturnType<T> ) { let running: ReturnType< typeof func > | null = null; return ( ... args: Parameters<typeof func> ) => { if (running === null) { running = func(... args); running.finally(() => { running = null; }); } return running; }; }Copy the code

The front end calculates price comparisons

In fact, our website, if there is no help page, is only one page site. There is no need to expose the API, but in order to try nuxt.js Programming Usage, the front end and back end can be nicely combined

Let’s import the fetch function we just wrote directly into SFC

import { response } from '@/api/functions/currency';

export default {
  async asyncData(context) {
    let currencyData;
    if (process.server && context) {
      currencyData = await response(
        context.req
      );
    } else {
      const data = await axios.$get(
        '/currency',
        {
          params: { ...someParams }
        }
      );

      currencyData = data;
    }
    return { currencyData }
  }
}
Copy the code

This way, even SSR does not need to send itself a /currency request.

If we don’t have any other pages, then we don’t have to expose the /currency API, just like nuxt.js is a template engine!

If you’ve written express.js, you’ll know that you’re going to write the data and then render the template, but here we’re going to write the front end, import the server function, and dump the request to get the data.

Isn’t it wild? (There should be an exclamation here.)

I’m going to skip the rest of the write interface and write sort.

Fix some minor problems

Remember to turn on extractCSS

Nuxt.js does not enable extractCSS by default, and if you invoke a UI library like I did and customize it, your HTML may grow to an outrageous length. Remember to enable it in nuxt.config.js

Nuxt.js packages AWS – SDK into the front end

I haven’t looked into the nuxt.js webpack issue yet, or maybe vue-loader (after all, we want to be fast).

This problem can be circumvented with the Nuxt plugin.

Create getData.server.ts in the plguins folder,

You can write a handler that relates to the server, you can mount it on the Vue, you can mount it on the context, you can mount it on anything, as long as it’s a global method that can be accessed in the SFC.

import Vue from 'vue';
import { response } from '@/api/functions/currency';
import { Context } from '@nuxt/types';

Vue.$serverGetCurrency = (context: Context) = > {
  return response(context.req);
};
Copy the code

Then go to SFC and change the Server method to this global method

if (process.server && context) {
  currencyData = await Vue.$serverGetCurrency(
    context
  );
}
Copy the code

In addition to the ts definition of the problem, declare next to the function no problem (source code)

Remember to refer to nuxt.js Plugins & Vue.js Augumenting Types for Use With Plugins

So sweet? Don’t lie to me because I don’t read much

Serverless itself is not a new thing, cloud function operating environment, object storage, cloud database, which is not a new thing in 2019 or 2020, but his idea solves the problem of online speed of small and micro services, for just starting growth enterprises, small companies without infrastructure, Or I have an idea that for a company that needs only one programmer, it is a very time-saving and labor-saving choice.

But…

Local development, cloud debugging ¿

Ask you are not afraid of local run well, put the cloud manufacturers there fried, and then debugging no door! Why is this so? Taking AWS as an example, have you ever wondered how cloud native handles issues like node_modules?

AWS Lambda deployment package in Node.js

The answer is, upload it along with your source code!

🐂🍺 my AWS, that is, if you have node_modules that rely on native capabilities, it will explode when uploaded, and you can’t detect any problems locally.

For example, NPM install with AWS lambda-Stack Overflow

Cost problem

Cloud service providers are also basic service providers, and they have helped you in Scaling and provided friendly interfaces. So many good things, of course, can’t be free. Behind the one-year free and seemingly low lambda, there are high bundled consumption and the overall loss of price-insensitive groups

I can’t directly compare the overhead of using Serverless to that of a traditional server, but using AWS as an example, the API Gateway used by Serverless at $3.50 per million requests should be a significant overhead for a normal business. Even getting a DDNS attack can be a bit scary if your house will still be there tomorrow…

In contrast, it is obvious that a good cloud server with unlimited traffic, exclusive memory, relatively stable CPU, and almost unlimited traffic (Fair Use) is a cheaper option to buy for only a few dollars more.

But I still fragrant

In large companies with their own basic Settings, operating their own cloud native, so appropriate delegation of some simple add, delete, change and check requirements to the front end, efficiency improvement should be beyond doubt.

The last

Above, I hope the whole idea of this article, or the code snippet, can give you some inspiration or inspiration.

Feel free to point out any questions you have about this article, and any comments you may have about this website I wrote for elementary school students.

Feel free to tip for this article (online begging)

(The begging link is in the website about)

(Don’t give me a tip, give me a thumbs up.)