summaryrefslogtreecommitdiff
path: root/posts/programming/2021-01-28-undefined-javasript-is-undefined-.html
blob: e12203b45bb7f0ea93ff30086ef8dc9e8ef89b37 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="/includes/stylesheet.css" />
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      property="og:description"
      content="The World Wide Web pages of Adam Carpenter"
    />
    <meta
      property="og:image"
      content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
    />
    <meta property="og:site_name" content="53hor.net" />
    <meta property="og:title" content="Undefined? JavaSript Is Undefined." />
    <meta property="og:type" content="website" />
    <meta property="og:url" content="https://www.53hor.net" />
    <title>53hornet ➙ Undefined? JavaSript Is Undefined.</title>
  </head>

  <body>
    <nav>
      <ul>
        <li>
          <a href="/">
            <img src="/includes/icons/home-roof.svg" />
            Home
          </a>
        </li>
        <li>
          <a href="/info.html">
            <img src="/includes/icons/information-variant.svg" />
            Info
          </a>
        </li>
        <li>
          <a href="https://git.53hor.net">
            <img src="/includes/icons/git.svg" />
            Repos
          </a>
        </li>
        <li>
          <a href="/hosted.html">
            <img src="/includes/icons/desktop-tower.svg" />
            Hosted
          </a>
        </li>
        <li>
          <a type="application/rss+xml" href="/rss.xml">
            <img src="/includes/icons/rss.svg" />
            RSS
          </a>
        </li>
      </ul>
    </nav>

    <article>
      <h1>Undefined? JavaSript Is Undefined.</h1>

      <p class="description">
        So I've been working on a web app for my mom. Nothing too fancy, but
        it's a store front for her glass art. It's an easy way for her to keep
        track of inventory, update photos of her products, and for people to
        shop and search and sort and browse through it. This backend is an HTTP
        service written in Rust. The frontend is a Vue.js app. I've used Vue and
        JavaScript many times before but I recently ran into an incredibly
        strange bug. One that I would have hoped JavaScript would have some
        guard against. But JavaScript is an undefined language.
      </p>

      <p>
        I have a small component that uses a file input to collect an image from
        the user. Then I append that file to a FormData and set that FormData as
        a Fetch API request body. So I've got fetch API sending
        multipart/form-data across the network to my backend. Awesome! The
        backend is supposed to take each field of the request, turn the chunks
        into a single stream of binary data, and write them out to an image.
        Everything on the front seems like it's working great, it fires off the
        request and throws no errors. But then the backend only sees a few bytes
        of this multi-megabyte image. Not awesome! short chunks on the back-end.
        The array of data in the API is less than ten bytes long, when this is a
        many-kilobyte file I'm trying to upload.
      </p>

      <p>
        At this point I'm relentlessly debugging, trying to find out what's
        wrong with the API. Why is it truncating the request down to a few
        bytes, where's the rest of the data? It took me forever to actually
        inspect what those few bytes are and, lo and behold they're ASCII for
        <code>undefined</code> The request happily stringified an
        <code>undefined</code> object, instead of maybe throwing a null
        reference or undefined error during request creation because that's just
        what JavaScript does. <em>The linter didn't even catch it.</em>
      </p>

      <p>
        You can see what the debugging logs looked like on the backend below.
        Note that the <code>&data</code> is the field that spells out
        "undefined". Also note that the file picker/FormData was constructed
        alright because the key for the image name is correct.
      </p>

      <pre>
		<code>
[src/handlers.rs:114] &field =
Field: application/octet-stream
  boundary: ---------------------------175314640631070190963311652907
  headers:
    "content-disposition": "form-data; name=\"clu.jpg\""

[src/handlers.rs:119] &chunk = Ok(
    b"undefined",
)
[src/handlers.rs:123] &data = [
    117,
    110,
    100,
    101,
    102,
    105,
    110,
    101,
    100,
]
ImageWrite("The image format could not be determined")
		</code>
	</pre>

      <p>
        The <em>working</em> JS is here (it was late at night and I was so
        donion rings I just fixed it and pushed it without saving the errors for
        posterity):
      </p>

      <pre>
	  <code>
let file = event.target.files[0];
if (!file) {
	return;
}

const fd = new FormData();
fd.append(file.name, file);

const response = await fetch("http://localhost:8000/photos", {
	method: "POST",
	body: fd
});

console.log(response);
	  </code>
	  </pre>
      <p>
        I've gotten frustrated by JS before but not like this. I don't know if
        TypeScript would have solved this issue but writing in a language that
        gets transpiled back into the language I'm trying to avoid doesn't seem
        like the way forward. I'm looking forward to Web Assembly as a way of
        using more type-safe languages in the browser.
      </p>
    </article>
  </body>
</html>