$30 off During Our Annual Pro Sale. View Details »

よくあるWebサービスのAPIを作ったらいろいろ勉強になった話/WebApplicationAPITips

decafe09
October 05, 2018

 よくあるWebサービスのAPIを作ったらいろいろ勉強になった話/WebApplicationAPITips

decafe09

October 05, 2018
Tweet

More Decks by decafe09

Other Decks in Programming

Transcript

  1. よくあるWeb
    サー
    ビスのAPI
    を作ったらいろいろ勉強になった話
    Umeda.go 2018 Autumn
    2018.10.03
    1

    View Slide

  2. 自己紹介
    @decafe09
    小野寺 俊也
    シナジー
    マー
    ケティング株式会社
    2

    View Slide

  3. 今日の話の背景
    メー
    ル広告の入稿ツー

    SI
    開発をしている部署がRails
    で開発
    Rails
    デキない人(
    私)
    がいざ運用をしようとするといろいろ躓く
    躓きながらも運用をしてビジネスが回るようになってくる →
    次のステップへ
    3

    View Slide

  4. 次の選択肢
    Rails

    精通しているメンバー
    がいない
    React + Go
    ・Go
    を使いたいという強い気持ち
    ・Go
    のテンプレー
    トエンジンを使ってみたが厳しい → Go
    はAPI
    で。
    4

    View Slide

  5. 入稿物
    件名
    本文(
    テキスト)
    本文(HTML)
    画像(HTML
    で使用する画像)
    5

    View Slide

  6. RESTish
    なAPI
    G
    E
    T /
    c
    o
    n
    t
    e
    n
    t
    s
    {
    "
    c
    o
    n
    t
    e
    n
    t
    s
    "
    : [
    {
    "
    i
    d
    "
    : 1
    ,
    "
    s
    u
    b
    j
    e
    c
    t
    "
    : "
    x
    x
    x
    "
    ,
    "
    t
    e
    x
    t
    "
    : "
    x
    x
    x
    "
    ,
    "
    h
    t
    m
    l
    "
    : "
    x
    x
    x
    "
    ,
    }
    ,
    .
    .
    .
    ]
    }
    P
    O
    S
    T /
    c
    o
    n
    t
    e
    n
    t
    s
    {
    "
    s
    u
    b
    j
    e
    c
    t
    "
    : "
    x
    x
    x
    "
    ,
    "
    t
    e
    x
    t
    "
    : "
    x
    x
    x
    "
    ,
    "
    h
    t
    m
    l
    "
    : "
    x
    x
    x
    "
    ,
    } 6

    View Slide

  7. 画像とかファイルはどうやって送られているのだろう?
    Content‑Type: multipart/form‑data
    MDN
    のリクエスト例を参考に見てみます。
    https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content‑Disposition
    7

    View Slide

  8. P
    O
    S
    T /
    t
    e
    s
    t
    .
    h
    t
    m
    l H
    T
    T
    P
    /
    1
    .
    1
    H
    o
    s
    t
    : e
    x
    a
    m
    p
    l
    e
    .
    o
    r
    g
    C
    o
    n
    t
    e
    n
    t
    -
    T
    y
    p
    e
    : m
    u
    l
    t
    i
    p
    a
    r
    t
    /
    f
    o
    r
    m
    -
    d
    a
    t
    a
    ;
    b
    o
    u
    n
    d
    a
    r
    y
    =
    "
    b
    o
    u
    n
    d
    a
    r
    y
    "
    -
    -
    b
    o
    u
    n
    d
    a
    r
    y
    C
    o
    n
    t
    e
    n
    t
    -
    D
    i
    s
    p
    o
    s
    i
    t
    i
    o
    n
    : f
    o
    r
    m
    -
    d
    a
    t
    a
    ; n
    a
    m
    e
    =
    "
    f
    i
    e
    l
    d
    1
    "
    v
    a
    l
    u
    e
    1
    -
    -
    b
    o
    u
    n
    d
    a
    r
    y
    C
    o
    n
    t
    e
    n
    t
    -
    D
    i
    s
    p
    o
    s
    i
    t
    i
    o
    n
    : f
    o
    r
    m
    -
    d
    a
    t
    a
    ; n
    a
    m
    e
    =
    "
    f
    i
    e
    l
    d
    2
    "
    ; f
    i
    l
    e
    n
    a
    m
    e
    =
    "
    e
    x
    a
    m
    p
    l
    e
    .
    t
    x
    t
    "
    v
    a
    l
    u
    e
    2
    -
    -
    b
    o
    u
    n
    d
    a
    r
    y
    -
    -
    boundary: Part
    の境界
    Content‑Dispositoin:
    ブラウザでインラインか添付ファイルかを判断するのに使用。
    直接ダウンロー
    ドさせたいときは、
    このヘッダー
    を付ける。
    リクエストでは、form‑data
    を先頭に name(
    フィー
    ルド名)
    と filename(
    元のファイル名)
    8

    View Slide

  9. Go
    でどう受け取るか
    どういう違いがあるでしょうか。
    net/http/#Request.FormFile
    net/http/#Request.MultipartReader
    9

    View Slide

  10. Go
    でどう受け取るか
    どういう違いがあるでしょうか。
    net/http/#Request.FormFile ← 1
    つだけ
    net/http/#Request.MultipartReader ←
    複数
    10

    View Slide

  11. net/http/#Request.FormFile
    f
    u
    n
    c (
    r *
    R
    e
    q
    u
    e
    s
    t
    ) F
    o
    r
    m
    F
    i
    l
    e
    (
    k
    e
    y s
    t
    r
    i
    n
    g
    )
    (
    m
    u
    l
    t
    i
    p
    a
    r
    t
    .
    F
    i
    l
    e
    , *
    m
    u
    l
    t
    i
    p
    a
    r
    t
    .
    F
    i
    l
    e
    H
    e
    a
    d
    e
    r
    , e
    r
    r
    o
    r
    ) {
    i
    f r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m =
    = m
    u
    l
    t
    i
    p
    a
    r
    t
    B
    y
    R
    e
    a
    d
    e
    r {
    r
    e
    t
    u
    r
    n n
    i
    l
    , n
    i
    l
    , e
    r
    r
    o
    r
    s
    .
    N
    e
    w
    (
    "
    h
    t
    t
    p
    : m
    u
    l
    t
    i
    p
    a
    r
    t h
    a
    n
    d
    l
    e
    d b
    y M
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    }
    i
    f r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m =
    = n
    i
    l {
    e
    r
    r :
    = r
    .
    P
    a
    r
    s
    e
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m
    (
    d
    e
    f
    a
    u
    l
    t
    M
    a
    x
    M
    e
    m
    o
    r
    y
    )
    i
    f e
    r
    r !
    = n
    i
    l {
    r
    e
    t
    u
    r
    n n
    i
    l
    , n
    i
    l
    , e
    r
    r
    }
    }
    i
    f r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m !
    = n
    i
    l &
    & r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m
    .
    F
    i
    l
    e !
    = n
    i
    l {
    i
    f f
    h
    s :
    = r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m
    .
    F
    i
    l
    e
    [
    k
    e
    y
    ]
    ; l
    e
    n
    (
    f
    h
    s
    ) > 0 {
    f
    , e
    r
    r :
    = f
    h
    s
    [
    0
    ]
    .
    O
    p
    e
    n
    (
    )
    r
    e
    t
    u
    r
    n f
    , f
    h
    s
    [
    0
    ]
    , e
    r
    r
    }
    }
    r
    e
    t
    u
    r
    n n
    i
    l
    , n
    i
    l
    , E
    r
    r
    M
    i
    s
    s
    i
    n
    g
    F
    i
    l
    e
    }
    11

    View Slide

  12. net/http/#Request.ParseMultipartForm
    f
    u
    n
    c (
    r *
    R
    e
    q
    u
    e
    s
    t
    ) P
    a
    r
    s
    e
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m
    (
    m
    a
    x
    M
    e
    m
    o
    r
    y i
    n
    t
    6
    4
    ) e
    r
    r
    o
    r {
    .
    .
    .
    m
    r
    , e
    r
    r :
    = r
    .
    m
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    r
    (
    f
    a
    l
    s
    e
    )
    i
    f e
    r
    r !
    = n
    i
    l {
    r
    e
    t
    u
    r
    n e
    r
    r
    }
    f
    , e
    r
    r :
    = m
    r
    .
    R
    e
    a
    d
    F
    o
    r
    m
    (
    m
    a
    x
    M
    e
    m
    o
    r
    y
    )
    i
    f e
    r
    r !
    = n
    i
    l {
    r
    e
    t
    u
    r
    n e
    r
    r
    }
    .
    .
    .
    r
    e
    t
    u
    r
    n n
    i
    l
    }
    12

    View Slide

  13. net/http/#Request.MultipartReader
    f
    u
    n
    c (
    r *
    R
    e
    q
    u
    e
    s
    t
    ) M
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    r
    (
    ) (
    *
    m
    u
    l
    t
    i
    p
    a
    r
    t
    .
    R
    e
    a
    d
    e
    r
    , e
    r
    r
    o
    r
    ) {
    i
    f r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m =
    = m
    u
    l
    t
    i
    p
    a
    r
    t
    B
    y
    R
    e
    a
    d
    e
    r {
    r
    e
    t
    u
    r
    n n
    i
    l
    , e
    r
    r
    o
    r
    s
    .
    N
    e
    w
    (
    "
    h
    t
    t
    p
    : M
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    r c
    a
    l
    l
    e
    d t
    w
    i
    c
    e
    "
    )
    }
    i
    f r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m !
    = n
    i
    l {
    r
    e
    t
    u
    r
    n n
    i
    l
    , e
    r
    r
    o
    r
    s
    .
    N
    e
    w
    (
    "
    h
    t
    t
    p
    : m
    u
    l
    t
    i
    p
    a
    r
    t h
    a
    n
    d
    l
    e
    d b
    y P
    a
    r
    s
    e
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m
    "
    }
    r
    .
    M
    u
    l
    t
    i
    p
    a
    r
    t
    F
    o
    r
    m = m
    u
    l
    t
    i
    p
    a
    r
    t
    B
    y
    R
    e
    a
    d
    e
    r
    r
    e
    t
    u
    r
    n r
    .
    m
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    r
    (
    t
    r
    u
    e
    )
    }
    13

    View Slide

  14. net/http/#Request.multipartReader
    f
    u
    n
    c (
    r *
    R
    e
    q
    u
    e
    s
    t
    ) m
    u
    l
    t
    i
    p
    a
    r
    t
    R
    e
    a
    d
    e
    r
    (
    a
    l
    l
    o
    w
    M
    i
    x
    e
    d b
    o
    o
    l
    ) (
    *
    m
    u
    l
    t
    i
    p
    a
    r
    t
    .
    R
    e
    a
    d
    e
    r
    , e
    r
    r
    o
    r
    ) {
    v :
    = r
    .
    H
    e
    a
    d
    e
    r
    .
    G
    e
    t
    (
    "
    C
    o
    n
    t
    e
    n
    t
    -
    T
    y
    p
    e
    "
    )
    i
    f v =
    = "
    " {
    r
    e
    t
    u
    r
    n n
    i
    l
    , E
    r
    r
    N
    o
    t
    M
    u
    l
    t
    i
    p
    a
    r
    t
    }
    d
    , p
    a
    r
    a
    m
    s
    , e
    r
    r :
    = m
    i
    m
    e
    .
    P
    a
    r
    s
    e
    M
    e
    d
    i
    a
    T
    y
    p
    e
    (
    v
    )
    i
    f e
    r
    r !
    = n
    i
    l |
    | !
    (
    d =
    = "
    m
    u
    l
    t
    i
    p
    a
    r
    t
    /
    f
    o
    r
    m
    -
    d
    a
    t
    a
    " |
    | a
    l
    l
    o
    w
    M
    i
    x
    e
    d &
    & d =
    = "
    m
    u
    l
    t
    i
    p
    a
    r
    t
    r
    e
    t
    u
    r
    n n
    i
    l
    , E
    r
    r
    N
    o
    t
    M
    u
    l
    t
    i
    p
    a
    r
    t
    }
    b
    o
    u
    n
    d
    a
    r
    y
    , o
    k :
    = p
    a
    r
    a
    m
    s
    [
    "
    b
    o
    u
    n
    d
    a
    r
    y
    "
    ]
    i
    f !
    o
    k {
    r
    e
    t
    u
    r
    n n
    i
    l
    , E
    r
    r
    M
    i
    s
    s
    i
    n
    g
    B
    o
    u
    n
    d
    a
    r
    y
    }
    r
    e
    t
    u
    r
    n m
    u
    l
    t
    i
    p
    a
    r
    t
    .
    N
    e
    w
    R
    e
    a
    d
    e
    r
    (
    r
    .
    B
    o
    d
    y
    , b
    o
    u
    n
    d
    a
    r
    y
    )
    , n
    i
    l
    }
    14

    View Slide

  15. Go
    のコー
    ドを読めば仕様がわかる!
    15

    View Slide

  16. 勉強になった面白いところ
    32MB
    以下ならメモリで処理、32MB
    超なら一時ファイルを作成する。
    c
    o
    n
    s
    t (
    d
    e
    f
    a
    u
    l
    t
    M
    a
    x
    M
    e
    m
    o
    r
    y = 3
    2 <
    < 2
    0
    )
    mime/multipart/formdata.go
    i
    f n > m
    a
    x
    M
    e
    m
    o
    r
    y {
    /
    / t
    o
    o b
    i
    g
    , w
    r
    i
    t
    e t
    o d
    i
    s
    k a
    n
    d f
    l
    u
    s
    h b
    u
    f
    f
    e
    r
    f
    i
    l
    e
    , e
    r
    r :
    = i
    o
    u
    t
    i
    l
    .
    T
    e
    m
    p
    F
    i
    l
    e
    (
    "
    "
    , "
    m
    u
    l
    t
    i
    p
    a
    r
    t
    -
    "
    )
    i
    f e
    r
    r !
    = n
    i
    l {
    r
    e
    t
    u
    r
    n n
    i
    l
    , e
    r
    r
    }
    s
    i
    z
    e
    , e
    r
    r :
    = i
    o
    .
    C
    o
    p
    y
    (
    f
    i
    l
    e
    , i
    o
    .
    M
    u
    l
    t
    i
    R
    e
    a
    d
    e
    r
    (
    &
    b
    , p
    )
    )
    i
    f c
    e
    r
    r :
    = f
    i
    l
    e
    .
    C
    l
    o
    s
    e
    (
    )
    ; e
    r
    r =
    = n
    i
    l {
    e
    r
    r = c
    e
    r
    r
    }
    .
    .
    .
    }
    16

    View Slide

  17. ちょっと話はそれますが
    strconv.Itoa
    の 99
    まではslice
    で切り出すだけの処理。
    c
    o
    n
    s
    t s
    m
    a
    l
    l
    s
    S
    t
    r
    i
    n
    g = "
    0
    0
    0
    1
    0
    2
    0
    3
    0
    4
    0
    5
    0
    6
    0
    7
    0
    8
    0
    9
    " +
    "
    1
    0
    1
    1
    1
    2
    1
    3
    1
    4
    1
    5
    1
    6
    1
    7
    1
    8
    1
    9
    " +
    "
    2
    0
    2
    1
    2
    2
    2
    3
    2
    4
    2
    5
    2
    6
    2
    7
    2
    8
    2
    9
    " +
    "
    3
    0
    3
    1
    3
    2
    3
    3
    3
    4
    3
    5
    3
    6
    3
    7
    3
    8
    3
    9
    " +
    "
    4
    0
    4
    1
    4
    2
    4
    3
    4
    4
    4
    5
    4
    6
    4
    7
    4
    8
    4
    9
    " +
    "
    5
    0
    5
    1
    5
    2
    5
    3
    5
    4
    5
    5
    5
    6
    5
    7
    5
    8
    5
    9
    " +
    "
    6
    0
    6
    1
    6
    2
    6
    3
    6
    4
    6
    5
    6
    6
    6
    7
    6
    8
    6
    9
    " +
    "
    7
    0
    7
    1
    7
    2
    7
    3
    7
    4
    7
    5
    7
    6
    7
    7
    7
    8
    7
    9
    " +
    "
    8
    0
    8
    1
    8
    2
    8
    3
    8
    4
    8
    5
    8
    6
    8
    7
    8
    8
    8
    9
    " +
    "
    9
    0
    9
    1
    9
    2
    9
    3
    9
    4
    9
    5
    9
    6
    9
    7
    9
    8
    9
    9
    "
    17

    View Slide

  18. アップロー
    ドされた内容のバリデー
    ション
    入稿規定というものがありまして。。。
    例)
    HTML
    golang.org/x/net/html
    でパー

    NG(
    ワー
    ド、
    文字、
    タグ、
    属性、
    属性値)
    ひたすら正規表現
    画像
    のちほど触れます
    18

    View Slide

  19. Regexp
    のとてもためになるTips
    参考:regexp
    との付き合い方‑go
    言語標準の正規表現ライブラリのパフォー
    マンスとアルゴリズム‑
    https://medium.com/eureka‑engineering/regexp
    との付き合い方‑go
    言語標準の正規表現ライブラリ
    のパフォー
    マンスとアルゴリズム‑984b6cbeeb2b
    c
    o
    n
    s
    t L
    i
    n
    k
    P
    a
    t
    t
    e
    r
    n = `
    h
    t
    t
    p
    s
    ?
    :
    /
    /
    (
    ?
    :
    [
    a
    -
    z
    0
    -
    9
    \
    -
    ]
    +
    \
    .
    )
    +
    [
    a
    -
    z
    0
    -
    9
    \
    -
    ]
    +
    (
    ?
    :
    /
    [
    a
    -
    z
    A
    -
    Z
    0
    -
    9
    _
    \
    -
    ]
    *
    )
    ?
    (
    ?
    :
    \
    ?
    ?
    v
    a
    r L
    i
    n
    k
    R
    e
    g
    e
    x
    p = r
    e
    g
    e
    x
    p
    .
    M
    u
    s
    t
    C
    o
    m
    p
    i
    l
    e
    (
    L
    i
    n
    k
    P
    a
    t
    t
    e
    r
    n
    )
    f
    u
    n
    c g
    e
    t
    L
    i
    n
    k
    R
    e
    g
    e
    x
    p
    (
    ) *
    r
    e
    g
    e
    x
    p
    .
    R
    e
    g
    e
    x
    p {
    r
    e
    t
    u
    r
    n L
    i
    n
    k
    R
    e
    g
    e
    x
    p
    .
    C
    o
    p
    y
    (
    )
    }
    19

    View Slide

  20. 画像
    大きさ、
    デー
    タサイズ、GIF
    アニメー
    ション
    Rails
    ではimagemagick
    で画像情報を取得 → image
    パッケー
    ジへ
    バイナリの判定は最初の数バイトで。
    i
    m
    p
    o
    r
    t _ "
    i
    m
    a
    g
    e
    /
    g
    i
    f
    "
    f
    u
    n
    c i
    n
    i
    t
    (
    ) {
    i
    m
    a
    g
    e
    .
    R
    e
    g
    i
    s
    t
    e
    r
    F
    o
    r
    m
    a
    t
    (
    "
    g
    i
    f
    "
    , "
    G
    I
    F
    8
    ?
    a
    "
    , D
    e
    c
    o
    d
    e
    , D
    e
    c
    o
    d
    e
    C
    o
    n
    f
    i
    g
    )
    }
    20

    View Slide

  21. GIF
    の仕様もわかりやすい
    https://golang.org/pkg/image/gif/#GIF
    t
    y
    p
    e G
    I
    F s
    t
    r
    u
    c
    t {
    I
    m
    a
    g
    e [
    ]
    *
    i
    m
    a
    g
    e
    .
    P
    a
    l
    e
    t
    t
    e
    d /
    / T
    h
    e s
    u
    c
    c
    e
    s
    s
    i
    v
    e i
    m
    a
    g
    e
    s
    .
    D
    e
    l
    a
    y [
    ]
    i
    n
    t /
    / T
    h
    e s
    u
    c
    c
    e
    s
    s
    i
    v
    e d
    e
    l
    a
    y t
    i
    m
    e
    s
    , o
    n
    e p
    e
    r f
    r
    a
    m
    e
    , i
    n 1
    0
    0
    t
    h
    /
    / L
    o
    o
    p
    C
    o
    u
    n
    t c
    o
    n
    t
    r
    o
    l
    s t
    h
    e n
    u
    m
    b
    e
    r o
    f t
    i
    m
    e
    s a
    n a
    n
    i
    m
    a
    t
    i
    o
    n w
    i
    l
    l b
    e
    /
    / r
    e
    s
    t
    a
    r
    t
    e
    d d
    u
    r
    i
    n
    g d
    i
    s
    p
    l
    a
    y
    .
    /
    / A L
    o
    o
    p
    C
    o
    u
    n
    t o
    f 0 m
    e
    a
    n
    s t
    o l
    o
    o
    p f
    o
    r
    e
    v
    e
    r
    .
    /
    / A L
    o
    o
    p
    C
    o
    u
    n
    t o
    f -
    1 m
    e
    a
    n
    s t
    o s
    h
    o
    w e
    a
    c
    h f
    r
    a
    m
    e o
    n
    l
    y o
    n
    c
    e
    .
    /
    / O
    t
    h
    e
    r
    w
    i
    s
    e
    , t
    h
    e a
    n
    i
    m
    a
    t
    i
    o
    n i
    s l
    o
    o
    p
    e
    d L
    o
    o
    p
    C
    o
    u
    n
    t
    +
    1 t
    i
    m
    e
    s
    .
    L
    o
    o
    p
    C
    o
    u
    n
    t i
    n
    t
    D
    i
    s
    p
    o
    s
    a
    l [
    ]
    b
    y
    t
    e
    C
    o
    n
    f
    i
    g i
    m
    a
    g
    e
    .
    C
    o
    n
    f
    i
    g
    B
    a
    c
    k
    g
    r
    o
    u
    n
    d
    I
    n
    d
    e
    x b
    y
    t
    e
    }
    21

    View Slide

  22. その他使用したパッケー

    PDF
    github.com/signintech/gopdf
    xlsx
    https://github.com/tealeg/xlsx
    xlsx
    はxml
    でカー
    ソルの位置情報も持ってる。
    空セルの判定 →
    カー
    ソルが乗ってるとデー
    タありの判定に。。。
    日付型などの情報 →
    エクセル上では、
    文字列とか日付型とか。。。
    zip
    defer
    でClose
    すると、
    空のzip
    になってしまう。
    参考: golang
    標準ライブラリから学ぶzip
    ファイルの構造
    https://blog.freedom‑man.com/zip‑structure‑golang/ 22

    View Slide

  23. まとめ
    Go
    のパッケー
    ジを読むと仕様理解ができる。
    なんとなくできていたものが、
    一つ一つ理解して積み重ねていける。
    23

    View Slide

  24. ありがとうございました
    24

    View Slide

  25. おまけ
    懇親会で質問してくださった方がいたので、
    他にも使ったパッケー
    ジを紹介します。
    github.com/gocraft/dbr :
    クエリビルダー(JST
    を扱うときはdialect
    を作りましょう)
    github.com/gorilla/mux :
    ルー
    ティング
    github.com/rs/cors :CORS
    github.com/rs/xid :id
    生成
    github.com/shogo82148/go‑sql‑proxy :SQL
    ログの出力で利用
    25

    View Slide