An Exploration of APIs, Versioning, & HTTP

An Exploration of APIs, Versioning, & HTTP

Released Monday, 10th March 2025
Good episode? Give it some love!
An Exploration of APIs, Versioning, & HTTP

An Exploration of APIs, Versioning, & HTTP

An Exploration of APIs, Versioning, & HTTP

An Exploration of APIs, Versioning, & HTTP

Monday, 10th March 2025
Good episode? Give it some love!
Rate Episode

Episode Transcript

Transcripts are displayed as originally observed. Some content, including advertisements may have changed.

Use Ctrl + F to search

0:05

Welcome to Fall Through Your Source

0:07

for Deep Conversations about technology, software,

0:09

and computing. I'm your host, Chris

0:11

Brando, also known as scriptable, and

0:13

on today's episode, we are talking

0:15

about APIs, versioning, and HDP, along

0:17

with a few other things, and

0:20

of course, we've got some un-pops

0:22

at the end. In this version

0:24

of the show, we're going to

0:26

be sticking to the content about

0:28

versioning and HDDP. If you want

0:30

to hear us talk about APIs

0:32

and identifiers, then you should head

0:34

on over to fallthrough.fm slash subscribe, where

0:36

you can sign up and get access

0:38

to that content. If you're not already, please

0:41

follow us on social media, and don't forget

0:43

to like and comment. And if you want

0:45

to see our lovely faces instead of just

0:47

hearing our lovely voices, head on over

0:50

to YouTube and smash that subscribe button.

0:52

And with that let's. It's

1:14

a fall-through. I probably don't

1:16

need an intro or something like

1:18

that. So we're here with our

1:20

panel, regular panel, you know, introduction.

1:22

Today we're talking about APIs, API

1:25

design, API implementation, maybe some API

1:27

testing. We shall see. And joining

1:29

us to talk about APIs is

1:31

the wonderful Jamie Tana. How are

1:33

you doing today, Jamie? Hey, I'm doing

1:35

great. And for our listeners that

1:37

don't know who you are,

1:39

would you mind introducing yourself?

1:41

Yeah, so I'm Jamie, I'm

1:43

a senior software engineer at

1:45

elastic and I'm working on

1:47

things like engineering productivity, but

1:50

over like the last decade

1:52

I've spent a load of time in

1:54

the API space. I am a blogger,

1:56

you may know, moved from some of

1:58

my lukewarm takes. I

2:00

most recently the co-maintainer of

2:03

the open APO to go

2:05

co-generator or APO Co-Gen, which

2:07

we spoke about on go

2:09

time a while back as

2:11

well. Yes, I remember that episode.

2:14

This is a fun episode.

2:16

So what's... Oh, gosh, Jamie, like,

2:18

what's your stance on versioning

2:21

then, right? Like, when is

2:23

a change, whether you're using,

2:26

like, URL pathing, or whether

2:28

you're using content negotiation, when

2:31

is a change become a

2:33

breaking change, and how does

2:35

that affect how you see

2:37

versioning for your API? Like,

2:39

what are your thoughts that used

2:41

to be required that are

2:44

now optional or not even

2:46

present? but also more importantly

2:49

if the behavior changes and

2:51

that is less easy to

2:53

work out because behavior being

2:56

like back-end how it's stored or

2:58

process or what do you mean

3:00

when you say behavior there? Yeah

3:02

so yeah and so for instance

3:05

like if you're saying to say

3:07

I want to create a new

3:09

user if that's in like the

3:11

V1 API creates the user and

3:14

actually does some like early on-boarding

3:16

steps or something like that or

3:18

like sends an on-boarding email maybe.

3:20

If in your V2 API you

3:22

just create the user and then

3:25

there's like a location head of

3:27

its return to something which then you

3:29

as the client need to go in

3:31

and then trigger the on-boarding step or

3:34

there's something slightly different that happens without

3:36

on-boarding email. I would say that is

3:38

a breaking change because even though

3:41

it may not be explicitly relied

3:43

on. by one of the consumers.

3:45

It is definitely a change in

3:47

underlying behavior. That's one of the

3:49

harder things that isn't necessarily documented

3:51

in your like API description, but

3:53

is something that consumers may be

3:56

relying on, may need to be

3:58

aware of. I remember all. lot

4:00

of debates around the

4:02

subjects when Go modules

4:04

came out with semantic

4:06

keyboard versioning. There are

4:08

lots of breaking changes

4:10

that aren't breaking from

4:12

the standpoint of API

4:14

signatures. And it's very

4:17

difficult to convey that

4:19

in the simplified model

4:21

of a single simver

4:23

string and semantic keyboard

4:25

version. You know, we're going

4:27

to have to like come

4:29

up with like a a

4:31

tone or something that plays

4:33

whenever any of us does

4:35

one of the classic things

4:37

we do like when I

4:39

go in a monologue or

4:41

when Dylan talks about semantic

4:44

import versioning like there's gonna

4:46

be some like noise encounter

4:48

because this is it want once

4:51

it can be match ding

4:53

that was me that wasn't

4:55

the soundboard that was that

4:57

was mad That's a very

4:59

nuanced area of discussion, like versioning

5:02

is important, but versioning is not

5:04

just your API signatures. You can

5:06

break an API by preserving the

5:09

signature, but changing the semantic behavior

5:11

of what you, what that API

5:13

does. So how are we telling

5:16

clients this then, right? Like how

5:18

are we, how are we communicating

5:20

the version changing? Because we've talked

5:23

about this earlier in the conversation

5:25

where we said that, you know,

5:27

your original storage model can leak and

5:30

then your business next week or next month

5:32

is going to change because your CTO said

5:34

we're going in the AI route or doing,

5:36

you know, they pivot. How do you handle

5:38

that then, right? Because it's going to happen.

5:40

The change is coming and your API, the

5:43

way you designed it yesterday, is no longer

5:45

relevant and needs to be changed for today's

5:47

users. How do you communicate that version to

5:49

your clients and how do you like bring

5:51

the old clients forward with you into the

5:53

new and greatest way of doing things? I

5:56

mean, I think the naive version of that is

5:58

you just stack towers and towers of. points

6:00

and eventually you say hey that

6:02

old one's gonna stop working right

6:05

but in there but is it though like

6:07

no you would ever stop working like I

6:09

can go look at our our like main

6:11

monolith API in point list and

6:13

it's like 800 of them right

6:15

yeah and 400 of those are probably

6:17

old and no one uses them

6:20

but they stick around because maybe

6:22

someone uses them and hot

6:24

take here I don't have the biggest

6:26

issue with that like in a

6:28

lot like having a many routes

6:30

stay alive? Yeah. Okay. In a

6:32

lot of ways, it's easier, like the

6:35

change manager of that is actually

6:37

easier than trying to version APIs.

6:39

Just like building, like, I mean,

6:41

it's the same strategy as slash

6:43

v2 slash v3, right? That's not

6:45

versioning your API. That's building new

6:47

in points. Those aren't the same

6:49

in points, right? And like, it's

6:51

not the most technically correct. But

6:53

I do think for your customers,

6:55

it's the easiest. to migrate, it's

6:58

the easiest to understand. I don't

7:00

know, it's hot take. It's understandable

7:02

and it's comprehensible. Like, it makes

7:04

sense to a human. Yeah, if I

7:07

have to tell my customer, our reporting

7:09

API, you now have to send this

7:11

weird version header, and then suddenly you've

7:13

got to negotiate the, like, the version

7:15

and everything, they're going to be like,

7:17

we're not going to use this. I

7:19

need to be able to put this

7:21

in a ETL job. I actually can't

7:23

even change. One of my, and not

7:26

so much anymore, but back in

7:28

my Windows days, one of my

7:30

favorite blogs was, it's called

7:32

The Old New Thing. It's

7:34

from a guy on the Windows

7:36

team, his name is Raymond Chin,

7:39

and he's on the compatibility

7:41

team. And he wrote for years

7:43

these explanations about the Herculean

7:45

efforts that the Windows team have

7:47

done over the years to make

7:49

sure that Lotus 123 from 1994

7:52

still works. on Windows 11. So

7:54

at that level, kind of, it

7:56

does cross over into that the

7:58

concept of API version. and kind

8:00

of like you said stacking in

8:03

points and like you have these

8:05

millions of consumers if you're wildly

8:07

successful who realistically you can't get

8:09

all of them a switch so

8:12

you have to account for it

8:14

on your they don't care about

8:16

your tech debt yes they're not

8:18

going to switch what they have

8:21

works for them so you're new

8:23

you're like you said your internal

8:25

refactor if it breaks them you're

8:27

for lack of a nicer way

8:30

to put it, you're failing

8:32

at your job. I don't know

8:34

if I agree with that, but

8:36

I want to hear, yeah, I

8:38

want to hear, I want to

8:40

hear other people's thoughts about this.

8:42

So I wrote a thing, I

8:45

wrote a little, a little,

8:47

I call it a thought

8:49

about this because I think

8:51

I've thought about this problem

8:53

a lot because like it bothers

8:55

me that. Like you almost wind up

8:58

feeling held hostage by your customers because

9:00

you don't want to let them down

9:02

or your consumers really, not necessarily customers.

9:04

You don't want to let them down

9:06

and they obviously don't want to change

9:08

things. Maybe can't change things without an

9:11

impetus, right? Like they won't change something

9:13

unless there's a reason for them to

9:15

change it. So if you're just like,

9:17

hi, please move over to my new

9:19

API. They're like, I have a giant

9:22

backlog. So unless I have to, no. And there's

9:24

a way we deal with this in the

9:26

broader world, and they're called contracts, right? You

9:28

write down a contract, and both sides have

9:30

to agree, this is what we've agreed on.

9:33

And what we essentially do now is we

9:35

have a contract, but the contract says, you

9:37

get to use this thing in perpetuity, right?

9:39

I mean, I know we sneak into the

9:41

terms of service and things like that, that

9:43

say, like, oh, we can turn this off

9:46

whenever we want, but like, the kind of

9:48

social contract or like, in effect contract we

9:50

have is you get to use this for

9:52

as long as you want and I think

9:54

one of the things we should do is

9:57

start just having explicit contracts that say hello

9:59

you can use this API, like here's all

10:01

the endpoints you get to use for this

10:03

amount of time. And you can encode that

10:05

as like, you know, a token that they

10:07

send or can be encoded into API tokens

10:09

like it generated. You can implement it however

10:11

you want. And, you know, at the end

10:14

of that time, maybe it's a year, they

10:16

can renew the contract. You can say, okay,

10:18

yes, we're gonna support these API endpoints for

10:20

the next year. here's your new contract.

10:22

But if at the end of

10:24

that contract, you're like, well, actually,

10:27

we don't want to maintain these

10:29

APIs anymore, well, then you go into

10:31

contract negotiations. So then you sit

10:33

down with the other side and

10:35

you say, okay, well, we don't

10:37

want to support this API anymore

10:39

because, you know, it's costing us

10:41

all that money, so, we'll allow you

10:43

to keep using it, but here's it,

10:45

but here's how much it's going

10:47

to cost you. Like, we don't want

10:50

to support this. Okay I'll pay that or

10:52

no I don't want to pay that and

10:54

if they don't want to pay that then

10:56

okay well here's the new contract that doesn't

10:58

have these API endpoints if you call them

11:00

you will get rejected and so and here

11:02

you go but if they do want it's

11:05

like okay well here you go and give

11:07

you the money and then you're done right

11:09

and you do that for each individual consumer

11:11

you have obviously you can automate this however

11:13

you want and you can you know make

11:15

the contracts however you know in depth that

11:17

you want them to be but fundamentally

11:19

the problem we have here is that

11:21

not everybody is a I don't think

11:24

we're going into this with a mindset

11:26

of Oh, this is a contract and

11:28

I don't think we're all purposefully

11:30

making in perpetuity contracts and we

11:32

need to get away from ourselves

11:35

making in perpetuity contracts because obviously

11:37

we would all like to change things

11:39

in the future. This also gets you

11:41

away from necessarily having just a version

11:43

of versions or even content type anything

11:46

into headers or anything like that because

11:48

the API token or the contract

11:50

can say what version of the API you're

11:52

using. Right. You can get a new contract

11:55

that says, okay. will be processed using the

11:57

V2 API and your old contract is the

11:59

V2. one API and then you choose in

12:01

your application which token you get and that.

12:04

will tell you that will inform the application

12:06

which version to send back to you. So

12:08

it solves, it definitely can solve the versioning

12:10

problem, but it also solves this larger problem

12:12

of being able to clean out some of

12:15

those older things that you have, because there

12:17

is a big problem of, is this API

12:19

still used? I don't have a way of

12:21

definitively knowing that. But you can say, if

12:23

you look in the contract database, no one

12:25

has a valid contract for this API endpoint,

12:27

then you know you can get rid of

12:30

it for whatever you want. Yeah, I guess

12:32

one of my concerns with that is friction.

12:34

So there's, first of all, you need to

12:36

have all that data available, which like

12:38

scrappy young startup maybe isn't going to

12:40

have that. But even like large

12:43

enterprises aren't generally building that

12:45

sort of information into new things

12:47

they're building. It's also like, say, I

12:49

want to come and play around with

12:51

your API. Do I now have to

12:53

go through a contract negotiation to just get

12:56

an API key to play around with

12:58

it the first time? No, not necessarily.

13:00

You could have just like, you could

13:02

have a shared contract or an automatic

13:04

contract that's just like, oh, it's like

13:06

the same way you get API tokens,

13:09

right? There's not to be something

13:11

necessarily different in that flow. You

13:13

could be like, here's your API

13:15

credential. This is how long it

13:17

lasts. And oh, here's the documentation

13:20

about what you're allowed to call

13:22

with it. And when you regenerate it,

13:24

that documentation might be different.

13:27

Basically. Here's the current published version

13:29

of this API. It's Q1 2025.

13:32

As a vendor, as a service

13:34

provider, we will support that version

13:36

of the API for one year

13:39

and we'll guarantee that. But

13:41

in Q1 of 2026, those APIs

13:43

are now subject to breakage. And

13:46

it kind of solves the implicit

13:48

in perpetuity thing that leads to

13:50

all the nasty compatibility shims and

13:53

windows to make DOS programs

13:55

from 1980 still work.

13:57

but without all the

13:59

extra. infrastructure requirement

14:02

that Jamie was calling out kind

14:04

of now you have to go

14:06

build that in and have the

14:09

system in place to go provision

14:11

contracts for every user and store

14:13

their API tokens and kind

14:15

of there's a lot of

14:17

investment potentially a lot of

14:19

investment to get that working

14:21

that a lot of early

14:23

stage systems just don't have

14:25

the time or the resources to

14:27

build. So what you described still

14:30

fits within what I was talking

14:32

about, right? That's just a, I

14:34

mean, you can conceptually understand it

14:36

as... There's only one contract that is negotiated

14:38

with everybody. And when you, it's like, it's

14:40

like terms of service, right? You don't write

14:42

terms of service for each individual user of

14:44

your website, but terms of service is still

14:46

a contract. So you can have a contract

14:49

that is just with anybody that uses your

14:51

service that is like, okay, well, there's no

14:53

negotiation for it. Like, here's what it is,

14:55

here's the API and points, after a year,

14:57

we get to break all of them if

14:59

we so choose. That's what it is, right?

15:01

But I think the thing about it is

15:03

that it puts explicitness on the whole situation,

15:06

which I think will shift people's minds

15:08

over time about how they use APIs

15:10

and how they consume APS and how

15:12

they build their own applications as well,

15:14

and what they are telling their customers,

15:16

because they think a lot of the

15:18

time it's, oh, I need this API

15:20

because my customers use this specific thing

15:22

in my application, and I haven't told

15:24

my customers that this app might stop

15:27

working, right? It's less now that we're

15:29

all subscription based, but definitely was a

15:31

thing in the past where people'd buy

15:33

an app and they'd be like, I

15:35

get to use this app forever. But it's

15:37

like, well, that's not really reasonable if,

15:39

you know, if people want to deprecate

15:41

things that, you know, are underneath you

15:43

or not directly in you as an

15:45

app developers control. This also opens up

15:48

the opportunity for if you do wind

15:50

up selling an app and... Like you're you you

15:52

as a as a person like I don't maintain

15:54

this version of the app anymore But someone or

15:56

maybe some big enterprise is like you know we

15:58

really need this, but we're it's an app for

16:00

a third party thing. Maybe they

16:03

can go to that third party

16:05

and be like, okay, we want

16:07

our own contract. And as long

16:09

as you've negotiated, as long as

16:12

you've put configurability in your app,

16:14

they can put their own contract

16:16

token in there. So you as

16:18

a developer don't have to get

16:21

involved at all. You don't have

16:23

to go back and care about

16:25

this old version of the app.

16:27

They can keep using it because

16:30

they've negotiated. what a contract could

16:32

be, right? Like in contract law,

16:34

if I just say, oh, let's

16:36

do this thing, we get a

16:39

hand, and we handshake, that's a

16:41

contract. So it doesn't have to

16:43

be some like in-depth, you have

16:45

lawyers and negotiation, it takes months

16:48

to do it. It's enough to

16:50

be that. It's just the explicitness

16:52

of this is what we are

16:54

providing for this amount of time,

16:56

and this is your ability to use

16:59

it. Right. It's it's something you need

17:01

to think about up front, not when

17:03

it actually you're ready to deprecate

17:05

something. You're talking about like having an

17:07

app, something we ran into on my

17:10

previous job was I mean, we had

17:12

people on very old versions of iOS

17:14

apps, right? And we had no way

17:16

to cleanly deprecate that, right? Like if

17:18

we if we change the APIs or

17:20

get rid of them, that app just

17:22

breaks in a way we might not

17:24

understand. So something we implemented was

17:26

a minimum version. for APIs that

17:29

returned like a explicit error that

17:31

said this app version is no longer supported

17:33

so we could pop a message saying like hey

17:35

if you want to keep using our app you

17:37

have to update right but we couldn't do

17:39

that on the oldest versions because we

17:41

hadn't implemented that code but that's like

17:43

a lesson you learn that like you

17:45

need to think about this stuff up

17:47

front like from the beginning. Otherwise you're

17:49

stuck. You just go get your time machine

17:52

and you go back and add that code.

17:54

before you thought about it. This is a

17:56

very nuanced interesting topic and I'm glad we're

17:58

talking about it honestly because I personally

18:01

haven't seen someone's API

18:03

that I'm like, oh, they're doing

18:05

versioning perfectly, right? This is amazing.

18:07

It sucks to have to say,

18:09

no, that thing is no longer

18:11

around, please migrate to the new

18:13

thing. And it's hard to convince

18:16

people that are on the old

18:18

thing that's working for them to

18:20

migrate. It's weird too, because we're in

18:22

the software field where software is malleable,

18:24

like we should be able to change

18:27

it almost at will. It's not like

18:29

we constructed a building, and it's like,

18:31

oh man, that V1 designer at calm,

18:33

I really wish we would have did

18:35

it differently, like let's go tear the

18:38

whole billion down, like we don't have

18:40

to do that in software. It's

18:42

much easier for us to change software,

18:44

yet we're much like more likely to

18:46

not change it, because we're like, it

18:48

works, it works, it works, it's fine.

18:50

contracts and burgeoning and stuff, it kind

18:53

of almost reminds me of like a

18:55

restaurant almost where you go in there and the

18:57

contract of you eating is whatever's on the

18:59

menu. And then you go there a month

19:01

later, the menu has changed and your favorite

19:03

item that you were used to using is

19:06

no longer there. And it's either you get

19:08

the new replacement item that's that's similar to

19:10

what you like to eat or you don't

19:12

use that API and you don't use that

19:14

restaurant and you go somewhere else. And it's

19:16

kind of what I'm feeling there, but

19:18

it's communicated. The idea is

19:21

that the service that's being

19:23

offered, the food that's being

19:25

offered, is communicated to all

19:27

the users. Yeah, I would say,

19:30

like you said, it's always nuanced

19:32

and there's gray area around what's

19:35

the right way to version

19:37

your API, but I think the

19:39

most common and the biggest mistake

19:41

that I see is not

19:43

versioning at all and discovering a

19:46

year in. that this needs

19:48

to change and I don't have

19:50

a way to version my API.

19:53

It's almost impossible to bolt

19:55

versioning on after the fact. Well

19:57

that's why you get slash

19:59

retoos. the most important thing

20:01

is you have to think

20:04

about versioning up front. Whatever

20:06

your specific implementation of versioning

20:08

ends up being, there's lots

20:11

of flexibility there, but you

20:13

have to account for versioning

20:15

in your system before there's

20:18

a breaking change. Because if

20:20

you need to go ad

20:22

versioning after it's already out

20:25

there, it's orders of magnitude

20:27

more difficult. Not impossible, but...

20:29

extremely difficult. Prime example,

20:32

go introducing major versions

20:34

and semantic keyboard versioning.

20:36

One of the bigger

20:39

problem areas is the V0 versus

20:41

V1 because there was no explicit

20:43

difference there. There was no line

20:45

in the sand to say now

20:48

this is V1. That's kind of

20:50

an example of when you do

20:52

versioning after the fact. It's much

20:54

harder, it's much more difficult, it's

20:56

harder for people to understand, it's

20:59

harder for you to implement. So

21:01

if I had to have any

21:03

bit of advice for anyone, it's

21:05

think about how you want to

21:07

handle versioning up front. Like that's

21:09

one of your first things that you need

21:12

to account for. And don't do whatever Go

21:14

do with V2 modules, don't do that. Sorry.

21:16

I think as well, like, on the topic

21:18

of like, thinking up from for versioning, one

21:21

of the things that I don't see a

21:23

lot of people doing, thinking generally

21:25

up from and doing a

21:27

lot of actual designing of

21:29

the API and considering

21:31

what sort of things should actually

21:34

be in that. You work on Open

21:36

API CodeGen, right? The project. So my

21:38

question to you is like, maybe does

21:40

versioning even matter, right? Could we just

21:43

keep our Open API... spec up to

21:45

date for our APIs and like AutoGen

21:47

our clients and servers and everything's happy

21:49

and everyone's always on the latest. Yeah,

21:51

we're all happy. Like is that a

21:54

world where we can be in where

21:56

versioning kind of goes away because we're

21:58

all just on latest? How do you

22:00

feel about that? So shot on to

22:02

know, because people don't keep their open API

22:05

specs up to date. And I mean

22:07

more on the consumer side. So my

22:09

previous company, we had quite a lot of

22:11

open API usage. And some of it was,

22:13

because I was the maintainer of our OOPI

22:15

Code Gen, so we were trying to do

22:17

a bit more of it. It was the

22:20

sort of thing that when a team would

22:22

first go to integrate with someone else's API,

22:24

they would generate some code. off the spec

22:26

that they had at that point. And then

22:29

they wouldn't update that spec until the

22:31

next time they needed to do a

22:33

load of work with it. And potentially

22:35

in that time there are new API

22:37

endpoints that are coming in. There are

22:39

documentation tweaks. There's different things that could

22:41

be of note. And so I think in

22:43

that case, because people aren't keeping up to

22:46

date, it is making that a little bit

22:48

more difficult. There are ways you can get

22:50

around that by like, I've written many a

22:52

post about it, like you can do things

22:54

like... You can sync the open API spec

22:57

and then regenerate the SDK. You can generate

22:59

the SDK in a more central place. There

23:01

are also lots of vendors that provide. Very

23:03

nice SDKs that always update and just like

23:06

send you PRs and say, hey, this is

23:08

updated now. But one of the issues is

23:10

that at some point there is going to

23:12

be a broken change. You are going to

23:14

have to modify the call sites of the

23:17

underlying code base. And I think

23:19

that's really the hard thing is even if

23:21

we like abstract it out with... a go

23:23

module that is a nice SDK. At some

23:25

point, someone still needs to go

23:27

in and make some tweaks to put

23:30

in some new required parameters or move

23:32

to a new function call. So then

23:34

would you say open API is usefulness

23:36

while it can generate SDKs and whatnot

23:39

and serves as that like, you know,

23:41

that documentation of your API's functionality, would

23:43

you say the open API spec

23:45

is more useful as documentation itself

23:47

to show the user like what

23:49

even the API is and how

23:51

it works? Is open API an

23:53

open API spec enough for documentation?

23:55

Do I not have to write

23:57

anything else except for that? So...

24:00

You can write a good enough

24:02

open APA spec with like good

24:04

levels of description and everything in

24:06

there. I still don't think it's

24:08

quite enough. I like there's a

24:10

number of very excellent folks in

24:13

the API community who are also technical

24:15

writers and rightfully so. I like you

24:17

can't just write a yammer file and

24:19

call it done but there needs to

24:21

be a little bit more than that.

24:24

But you can get a good chunk

24:26

of the way if you have a

24:28

very reasonable. Open API spec with descriptions

24:30

and summary as an examples, which can

24:32

then be used by tools to either

24:34

generate service-side or client-side boilerplate. You can

24:36

generate like mocks, so you can actually

24:39

test out that API without actually having

24:41

to hit it, and things like that

24:43

are quite useful, because they also give

24:45

you a more realistic view of what

24:47

the API will look like. So is

24:49

that where you're looking for when you're

24:51

going to a new API when you're

24:53

trying to consume a new API that's

24:55

not yours, right? Are you looking for

24:58

that open API spec? Are you looking

25:00

for good documentation? Are you looking for

25:02

MOCs? Like what are you looking for? That

25:04

makes you say, wow, this API is like,

25:06

I understand it, you know. So I will

25:08

first try and find the API docs

25:11

for whatever the API is. If

25:13

they look nice, generally there's an

25:15

open API spec underneath. and they've

25:17

got a tool that is generating

25:19

out most stocks. So then I

25:21

will also take a look at

25:23

the spec. I will, for instance,

25:25

throw it into a couple of

25:27

different open API to code generators,

25:29

because one of the difficulties with

25:31

open APIs, well, we see this

25:33

with OPA CodeGen, is no two

25:35

tools are equal. So for instance,

25:37

like open API 3.1, came out

25:40

several years ago, kind of

25:42

remember how many years. We

25:44

don't have support yet. because

25:46

the primary go library for

25:48

open API doesn't yet have

25:50

support because it's hard. So

25:52

you're saying there's a versioning

25:54

problem, which is all we've been

25:56

talking about this whole time. Yeah, okay.

25:58

I understand. And then. Like even then

26:00

it's yeah so some parts of the

26:03

ecosystem don't have support for it there

26:05

are like lots of nuances to open

26:07

API that makes it really awkward to

26:09

work with and again it goes

26:12

back to like that conversation

26:14

about technically correct versus what

26:16

is practical so you can write a

26:18

really powerful open API spec that

26:20

perfectly describes a load of conditional

26:22

things that may or may not

26:24

happen in place but if you

26:26

can't use any tools with that

26:28

definition you now have to go and

26:30

write the code anyway, you now have

26:33

to implement it all yourself anyway. So

26:35

it's a little bit like, some of

26:37

it is plain to like the lowest

26:39

common denominator, while also

26:42

trying to like nudge the playing

26:44

field up. I think maybe a

26:46

valid signal for open API is

26:48

maybe it's different for others, but

26:50

in my work experience, very few

26:52

people are actually handwriting open

26:54

API specs. I see lots

26:56

of effort around... I do

26:58

that. Oh, here's my... here's

27:00

my go code and uh...

27:02

Go Restville is an example

27:05

where they have an open

27:07

API generator from your rest

27:09

mappings in code, where you

27:11

write the code and then

27:13

dump the open API spec

27:15

from it, rather than author

27:17

the spec explicitly. I mean,

27:19

I've touched it a few

27:21

times. Handwriting open API is tedious.

27:23

at best. I mean all documentation

27:25

is tedious. It's it's very verbose.

27:28

It's very labor intensive to hand

27:30

write an open AP aspect. I

27:32

mean writing gamble is just especially

27:34

like I've been at places where

27:37

like the open AP aspect was

27:39

like 3,000 lines in the animal.

27:41

I was like editing that is a

27:43

nightmare. Terrible. However, yeah I so

27:45

I agree writing it is not the

27:47

best but I still prefer doing that.

27:50

and at least for me it's

27:52

so some of it's maybe ADHD

27:54

and trying to get the thoughts

27:57

across and like I think

27:59

through writing. find in particular like

28:01

doing that up front what should this

28:03

contract actually look like and then not

28:05

just like okay great I've done some

28:08

yam-old let's go I then will actually

28:10

like use an open API mocking tool

28:12

and that will then give me an

28:14

actual representation of what that API looks

28:17

like and I've actually caught a number

28:19

of things there where it doesn't actually

28:21

match what I originally intended but there

28:23

is then that balance of but it

28:26

takes time to do that. I could

28:28

just go and write the code, but

28:30

also like the code that I

28:32

write may not actually be the

28:34

design that actually we wanted. And

28:36

so it's that balance of trying

28:39

to give yourself enough time to

28:41

actually work out what you want

28:43

to be doing and what you

28:45

want to be providing to your

28:48

users. And yeah, I'd say generating

28:50

code, generating spec from code is

28:52

better than no documentation at all.

28:54

And that's the other thing is

28:57

a lot of people will. just

28:59

handwrite all the documentation and that

29:01

is painful to work with, it's

29:03

painful to update and everything. So

29:05

yeah, if you can generate it

29:08

be some of it, do

29:10

that. And it's probably an

29:12

outcropping from my experience but

29:14

I'd much prefer writing

29:16

API specs in protobov

29:19

syntax than to go write an

29:21

open API spec. It's the

29:23

same thing. with essentially a

29:25

different syntax, but I find

29:27

protobuff, ideal, easier to read

29:30

and follow than open ABI.

29:32

Even though I haven't done

29:34

much protobuff stuff, I think

29:36

I agree. Like of the

29:39

bits I've seen, that does

29:41

seem quite reasonable. And I

29:43

mean, like I mentioned, even

29:45

the beginning of my career

29:47

doing calm on Windows, it

29:49

was very similar ideal based.

29:51

structured, this is an interface,

29:54

and here are the methods, and

29:56

here are the messages, kind of

29:58

structurally similar to prototype. So that

30:00

was a natural thing for me.

30:02

Coming from calm ideal way back

30:05

when and then spend a long

30:07

time doing kind of in the

30:09

world of magic. Microsoft Silver Light,

30:12

a lot of.net framework stuff where

30:14

the mechanics of APIs were, you

30:16

were insulated from that. Kind of

30:19

you didn't have to think

30:21

about the mechanics of APIs.

30:23

And then coming back to go

30:25

after a long time and getting

30:27

back into. And getting back into.

30:29

this idea of how do I define my

30:32

APIs? Doing protobuff and GRPC

30:34

felt much more natural than doing

30:36

open API and HDDP rest. How

30:38

do we avoid? Like I'm all

30:40

in favor of generating things, whether

30:42

it's writing an open API spec

30:44

by hand and generating code, whether

30:46

it's writing codes that generate the

30:48

open API spec or some... combination

30:50

in the middle of those. I

30:52

am in favor of that because

30:55

when you have a very large

30:57

API, it's going to be very

30:59

tedious to keep that up today

31:01

manually, right? Like humans going in

31:03

and editing things, it's going to be

31:05

very tough. But when you, when a

31:07

lot of developers say I generate things,

31:09

it's often a way of them saying I'm

31:12

too lazy to care about this and I

31:14

don't want to put any thought

31:16

into it. And I've seen that,

31:18

where like the documentation for the

31:20

Foo API is like the Foo

31:22

endpoint manages Foo Resources. Yeah, like

31:24

no duh, of course it does,

31:26

that's what I'm calling. But I

31:28

want more than that as a

31:30

description. So how do you like

31:33

balance that in your APIs that

31:35

you're creating? Like how do you

31:38

balance, you know, no documentation or

31:40

bad documentation or like good

31:42

documentation? How do you like find

31:44

that sweet spot? that was like, who

31:46

manages food? I'd just be like, just

31:48

delete it. Like, I prefer to

31:51

have no documentation than documentation like

31:53

that. Yeah, like, you have to

31:55

bring people along on, like, the

31:57

culture of documentation. That is the

31:59

answer, like, not. everyone enjoys writing

32:01

documentation but it is very

32:03

important to be honest people are

32:05

probably not going to read it

32:07

but for the few that do it will be good

32:10

as I say I find that writing the

32:12

documentation helps me have that empathy

32:14

for the user okay what are the

32:17

people actually trying to get out to this

32:19

what of what am I trying to solve

32:21

for them more generally and trying to

32:23

get people in that mindset can help

32:25

not everyone's there not everyone

32:28

has that experience and that skill

32:30

set, but it's something that

32:32

everyone can develop. I definitely

32:35

have found that I do

32:37

a better job of it

32:39

since I've kind of shifted

32:41

to that mentality. Like documentation,

32:43

for documentation's sake, kind of

32:46

the go-linter warning, hey, you

32:48

have this exported symbol with

32:50

no comment, so we're going to yell

32:52

at you. And people go right, fool,

32:55

fool's the bar. That's not a

32:57

useful comment, but it makes

32:59

the complaint go away. Since

33:01

I've kind of made myself

33:04

mentally shift to documentation is

33:06

to explain to your consumers

33:09

how they're supposed to interact

33:11

with this. And then kind of

33:13

taking it, like you said, Jamie,

33:15

from the standpoint of if I

33:18

go and your example of generating

33:20

a client from the spec, is

33:22

like a good, I've done that

33:24

myself, kind of, If I take

33:26

this spec that I've defined and

33:28

then I generate the code and then I

33:31

go try to use it, does it work

33:33

the way that I think it's going

33:35

to work? Do the semantics actually

33:37

behave the way that I'm thinking

33:40

they do or is it

33:42

actually clunky and difficult to

33:44

use to kind of make

33:46

that mental shift to you're

33:48

not writing documentation for documentation

33:50

sake? You're writing documentation as...

33:52

an instruction manual for how

33:54

to use your thing. Kind

33:56

of along those lines. I

33:58

do think when I start with

34:01

documentation versus end with documentation, I

34:03

end up with a better design,

34:05

right? Writing the documentation first to

34:07

me is like part of that

34:09

design exploration, and it's the

34:11

easiest way to to think about a

34:14

design, just writing the documentation. I don't

34:16

know where I'm going with that, but

34:18

I guess you should try to design first,

34:20

but not. Yeah, I think that like, I think

34:22

you all, like, so what I wanted to say

34:24

is that, like, like, I think the problem

34:26

is like an upstream problem here, and

34:28

I think. kind of what all of

34:30

you said are indicative of that, of like,

34:32

I think that you need to do like

34:35

the abstract API design. Like I think part

34:37

of the problem we have is that we

34:39

don't do that abstract API design.

34:41

We try to just implement an

34:43

API, whether that's writing in some

34:45

IDL or writing some open API.

34:47

And then I think more importantly,

34:49

we only implement one version of

34:51

that API, whether it's in HDP

34:54

or in GRPC or in GraphQL.

34:56

And I think that's part of

34:58

the problem here is that we're

35:00

not like, GRPC, GraphQL, HDP, even

35:02

rest as a concept as a

35:04

whole. Those are not, those are

35:06

your transports. Those are your way

35:08

of communicating with the thing you're trying

35:10

to communicate with. They are not the

35:13

thing themselves, but I think we treat

35:15

them. as the thing itself a lot

35:17

of the time. And they're insufficient for

35:19

that. They're not built for that. Like,

35:21

there's no good way, I think, to

35:23

write any IDL and have it contain

35:25

enough information to be sufficient, because there's

35:28

so much other stuff you need to

35:30

document that really, I think, a lot

35:32

of the time belongs in prose or

35:34

needs to be added as some sort

35:36

of extension or we need to evolve

35:38

the format. An example of this is,

35:40

I was trying to use GitHub Graphual

35:42

API. It's very well documented and there's

35:45

lots of information about you know

35:47

this these fields mean this and

35:49

these types mean this and all

35:51

of that but there's absolutely no

35:53

information about permissioning so I don't know

35:55

if say a get-up app can actually call

35:57

this graph can you can call this graph

36:00

GraphQL mutation or if it can query

36:02

for this field like that information is

36:04

completely missing and there's not an easy

36:06

way to actually go ascertain that besides

36:08

actually building the thing and trying it

36:10

out which can be difficult or if

36:12

you're talking about something like that actually

36:15

charges you money it could be expensive

36:17

and like that information doesn't necessarily have to

36:19

live in GraphQL but it should live somewhere

36:21

like I had to file a get up

36:23

support ticket to be like can I call

36:25

this API? from a, you know, from a,

36:27

what, GitHub app. And they came back and

36:29

looked, no, you're not allowed to call this

36:31

class of APIs. Great. That would have been

36:33

nice if you had put it somewhere else

36:35

where I could have found it. Or since

36:38

it's a GraphQL API, you won't actually get

36:40

a four or three, you'll get a 200,

36:42

and you have to go read the response

36:44

body to get the permission error. Well,

36:46

yes. Which is not technically wrong. But

36:48

that's a that's a that's a tangent.

36:50

So okay. No, that's a tangent. We're

36:52

going to come back to though. Okay.

36:55

Okay. We are going to revisit that

36:57

one. Don't you worry. I am writing

36:59

that down. That is the most common

37:01

source of table flips for me every

37:03

time I touch anything graph QO. It's

37:06

like it's a 200. Your request

37:08

was processed successfully. Okay. Fine.

37:10

We can get internet because it is

37:12

related to what I just said. Okay.

37:14

So I was saying how. You need

37:16

to have multiple, we really should have

37:18

like at least two, right? Like I think

37:20

it's, I don't like that, get hub doesn't

37:22

have equivalence between their two APIs, but

37:25

they do have like an HDP slash

37:27

rest API and a graphical API. And

37:29

the reason I think that's good is

37:31

that you, it helps you not encode. the

37:34

semantics of your transport into your

37:36

API. And what you said, Dylan,

37:38

is a good example of when

37:40

people encode the semantics of their

37:42

API into their transport, right? Because

37:45

what 400 errors are telling you

37:47

is that the HDDP request was,

37:49

in the case of 400 errors,

37:51

like malformed in some way by the

37:54

client, right? 400 is for client

37:56

malformations, 500 or something wrong with

37:58

the server, 200 is okay. And the

38:00

thing about GraphQL is that if it

38:02

returns a response to you, and

38:04

that response having an error in it

38:07

isn't incorrect because the HDP request was

38:09

processed successfully, it just resulted in an

38:11

error. But that error wasn't because of

38:13

something at the HDP layer, the error

38:15

is because of something behind the HDP

38:18

layer in your business logic. Right so

38:20

you said so this comes up a

38:22

lot if you have like list of

38:24

things or you want to process things

38:27

in batches if half of it succeeds

38:29

and half of it fails That's not

38:31

an HDPDP request failure the HDPD request

38:33

got through it got processed It was

38:35

fine. There was something within the HDPD

38:38

request at a lower level or higher

38:40

level depending how you want to look

38:42

at it that was the error and

38:44

the place where that error message should

38:47

be is not at the HDPD level

38:49

But at the kind of application that

38:51

you get back So it's, you know,

38:53

the request failed successfully or whatever it

38:56

is, right? It's that sort of thing,

38:58

but it makes sense because you need

39:00

to understand like the layering at the

39:02

end of the day, the layering

39:04

is important. And when you try

39:07

and put errors at the wrong

39:09

errors at the wrong layer, and

39:11

when you try and put errors

39:13

at the wrong layer, you tend

39:15

to start to confuse yourself about

39:17

what you should actually be status

39:19

code that says. partial success.

39:21

But in the context of

39:24

HDP, that doesn't make any

39:26

sense. Either the request succeeded

39:28

or it didn't. It got there

39:30

was process or it didn't. That

39:32

reminds me of, going back to

39:35

my Windows Days, the database API

39:37

in the calm days, everything was

39:40

integer error codes. And there

39:42

was a standard error code that

39:44

was DB underscore S for

39:46

success, underscore errors occurred. So

39:49

it's a success code to tell you

39:51

that errors occurred. Back to like the

39:53

HDFP version of it. It feels a

39:55

lot like the content negotiation where content

39:57

negotiation is the correct way to do

39:59

it. but you have to like cater

40:01

to the lowest common thing and people

40:03

expect the air in HDPD. So like

40:06

is it wrong to do it because

40:08

it's what people expect or like how

40:10

far outside the normal boundaries can you

40:12

go with an API before it's like

40:14

too much new information for our consumer

40:16

to parse right like if you created a

40:19

completely correct HDPI like half of

40:21

developers out there would get that

40:23

in their hands and be like

40:25

this doesn't make sense this is

40:27

horrible. I mean, the piss forks

40:29

would come out instantly.

40:31

I mean, you can always, that's the

40:33

thing about the HDP as well. Like,

40:35

HDP and rest as a

40:37

whole, but definitely HDP is

40:39

incredibly flexible. So you could

40:41

say, okay, well, like. We're going

40:43

to return errors unless you include this

40:46

header that says, okay, we actually are

40:48

going to do error processing the right

40:50

way, right? Or you could just say,

40:53

I'll just accept application Jason and we'll

40:55

just run the regular way, but if

40:57

you can send us this other way,

41:00

but if you can send us this

41:02

other thing and we'll just run the

41:04

regular way, but if you can send

41:07

us this other thing and we'll, you

41:09

can send us this other thing and

41:11

we'll be, send us. default way of

41:13

thinking about things, and unless you document and

41:16

tell them explicitly that that's not how it

41:18

works, they're going to go with that assumption.

41:20

So I think the problem is less that

41:22

people are assuming it works one way because

41:24

they're used to it, and more of that,

41:26

we haven't explicitly told them that this isn't

41:29

how this thing works, and if you want

41:31

to use it, this is how you're going

41:33

to have to use it. And I think

41:35

we need to not just go with

41:37

the lowest common denominator all of the

41:39

time, because that ratchets us down to

41:41

a place where we're just stuck, where

41:43

we can't evolve forward, where we're just

41:45

kind of trapped for a long time,

41:47

right? I mean, that's the issue with

41:49

API versioning, right? Yeah, you can make

41:51

a V2 and a V3 and a

41:53

V4, but people will just sit on

41:55

V1 forever, and you're kind of stuck

41:57

maintaining that implementation detail for the longest

41:59

time. And I think we as an industry

42:02

need to stop being stuck because it's

42:04

causing us problems, right? Yeah. People

42:06

are using HDP very wrong. We should

42:08

not stick ourselves in the mud because of

42:10

that. We should start making the changes because

42:13

we won't in 10 years have people use

42:15

HDDB right if we don't start now, even

42:17

if it's hard. Yeah, before we go too

42:19

far off of it, I do want to

42:22

say I very much agree with the point,

42:24

your point, Chris, about separating transport

42:26

from semantics from semantics. can't

42:29

even count the number of

42:31

times I've had that just

42:34

very similar discussions about kind

42:36

of you built this rest and

42:38

it doesn't work GRPC or

42:40

kind of what I was

42:42

talking about earlier where people

42:44

want to put database tags

42:46

and Jason marshalling tags in

42:49

their generated protobuffs trucks

42:51

because they want to also

42:53

use it for the rest API

42:55

kind of the rest and

42:57

GRPC and various things, hand-coded

42:59

UDP packets with your own

43:02

hand-rolled serialization format, those are

43:04

all transports. There are how

43:06

to get data from one point

43:08

to another. That's not the

43:11

semantics of the API. And what

43:13

you're designing is the semantics

43:15

of the behavior, not the

43:17

mechanics of the transport. Yeah.

43:19

I think Jamie had something I wanted

43:21

to say, but before that I want

43:24

to tag on to that of... Also,

43:26

if there's something your transport doesn't support,

43:28

you don't necessarily have to implement

43:30

it. Like, it's not incorrect. Like, the reason

43:32

I said GitHub's API annoys me in that

43:34

the HDP API and the Graphual API aren't...

43:37

equivalent isn't because like there's things that GraphiO

43:39

can do that HDB can't do it's because

43:41

there's they can both do equivalent things but

43:43

there was something that you know maybe in

43:46

a GRPC API is only doable over GRPC

43:48

and you can't do over a Graphi or

43:50

HDP it's fine to have it that way

43:52

and be like sorry this functionality can only

43:54

be done over this one interface because this

43:57

interface allows it so just wanted to make

43:59

that point. Oh yeah mine was again

44:01

an early unpop which was off the

44:03

back of you saying about like having

44:05

issues with being on v1 so you

44:08

should just say on v0 and always

44:10

break things and always keep

44:12

pushing up breaking changes and

44:14

I'm with you man I'm with you

44:16

yeah I'm with you yeah like honestly

44:19

if you can't be bothered to update

44:21

your client code then is it really

44:23

load bearing in your system yeah v0.

44:25

infinity I was going to ask a

44:28

quick question around HSP status code since

44:30

we opened up that that door. Delets.

44:32

I want to delete. I want

44:34

to do HSP delete. Am I... What's

44:36

the item put in way of doing

44:38

that? Do I always return to a

44:40

4? Do I return to a 4

44:42

when I actually do the deletion and

44:44

then do I return 404? When, you

44:47

know, there's no actual deletion being occurred

44:49

anymore? Or do I always return 404?

44:51

What's everyone's thoughts around around

44:53

this? I don't think there's a

44:56

correct answer to that. I

44:58

think the default to blind

45:00

deletes, like if you're trying

45:02

to delete something that

45:05

doesn't exist, we just

45:07

ignore it. And what do you

45:09

send back to the client? 200.

45:12

Or 200. Or 200. Okay, I've

45:14

seen people do two or fours.

45:16

I'm kind of against

45:18

most non-200-200 errors, like

45:20

other than just 200. I

45:23

think the other 200 errors are

45:25

very, especially 201. I think 201

45:27

accepted is like a very important

45:30

one. Yeah. That feels very hand-wavy.

45:32

Like, I have received your request,

45:34

maybe it worked, maybe it didn't,

45:36

maybe it'll fail at some point

45:38

in the future, we'll see what

45:41

happens. Which I always thought it's

45:43

very hard. Too accepted, not 201.

45:45

No, it's not really. I mean,

45:47

it's... Okay. This is another thing.

45:50

It's only handlavy if you see

45:52

your application transaction as a single

45:54

HDP request, which is not how HDB

45:56

works either, right? You have 202 accepted

45:58

and then something with. in the response

46:01

that you get should tell you how

46:03

to find the status. Yeah, what

46:05

the eventual status could be,

46:07

right? Because accepted means like,

46:09

hey, I got it, but I

46:11

haven't necessarily started processing yet. I'll

46:14

process it at some point. And

46:16

you can give them maybe a

46:18

location header that tells them where

46:20

to find it. Or maybe there's

46:22

a link header that gives it.

46:24

But there's options. So you have

46:27

to add more to it. on

46:29

polling or something like that, or

46:31

we'll send you an email, or

46:33

whatever, right? But it's semantically telling

46:36

you something that I don't

46:38

think 200 encodes well. Yeah, that's

46:40

fair. Yeah, kind of to Ian's point,

46:42

I'm kind of in the same

46:44

camp. I've never liked the idea

46:47

of returning an error code when

46:49

you attempt to delete something that

46:51

doesn't exist. Like, that's not a

46:53

failure in my mental model. So

46:56

if you send a delete. So

46:58

delete is not going to be a 404.

47:00

Oh, no. What? Yeah, I've seen people delete.

47:02

Not found for a delete of a

47:04

thing that doesn't exist. I've seen people

47:06

do it where the first requested

47:08

delete was the 204, right? Like

47:11

no content, because there was actually

47:13

something to delete and the delete

47:15

that happened. And then the follow

47:17

request was a 404, because there

47:19

was nothing to delete, and it

47:21

didn't do anything. And I'm like,

47:23

that's probably the most correct. Is

47:25

it, though? Yeah, I think it is

47:27

the most correct. So I guess it

47:30

depends on really how you want to

47:32

see what are resources like if a

47:34

resource is like if it's a thing

47:36

that actually like exists within your in

47:39

your database and you have now deleted

47:41

it then yes the proper HDB status

47:43

code for anything you do on it

47:46

should be 404 like that thing doesn't

47:48

exist anymore. Many resources conceptually

47:50

aren't really that Like if

47:53

you delete like a user you haven't deleted

47:55

the person so like I don't know it

47:57

really just depends on how you want to

47:59

conceptualize what a resource is, whether you

48:01

want to send back a 404 or

48:03

a 204 or, you know, whatever. And

48:06

I guess that's where it always

48:08

kind of irked me is you

48:10

send a delete for a thing and

48:12

that thing is valid at the

48:14

time that you send the request

48:17

and the system deletes it.

48:19

Then a 404 response becomes

48:21

nebulous because does that mean

48:23

you try to delete something

48:25

that wasn't there and it

48:28

was a bad request? As in

48:30

that thing you wanted to delete

48:32

isn't a thing or is the 404, hey

48:34

your thing is gone now so it

48:37

does not exist. Well I don't think

48:39

sending a 404 for a

48:41

delete request that deletes something

48:43

is correct. That seems incorrect

48:46

because the thing did exist

48:48

when you made the HDP request.

48:50

So you took the request

48:52

you did something and now

48:54

you're responding to the request.

48:56

And whereas like a 404 is like

48:59

when you made the request that thing

49:01

didn't exist, what it was process that

49:03

thing didn't exist, if in the process

49:05

of processing it that they no longer

49:07

exist, then that's a that's a different

49:09

status code. That's a different thing. You

49:11

know what? This is like, I like

49:13

this, this question because it's, it really

49:15

makes you think about where the transport

49:18

ends and where your application logic begins.

49:20

And like, the more we talk about

49:22

this specific example, the more I'm like crap.

49:24

At this point, I'll just send back

49:26

the 200 okay with a response body

49:28

and let the user figure it out

49:31

there. Like, because I don't know the

49:33

answer. Like the response body is

49:35

an important thing, right? I mean,

49:37

sending back 204 don't content means

49:40

there's like literally nothing, you can't,

49:42

nothing, you can't include a body.

49:44

There's, there's nothing there. So in

49:47

the case of a delete, sending a

49:49

200 and then more information is a

49:51

good thing. that Jamie sent us

49:53

a link in the chat that

49:55

I I immediately clicked with no

49:57

I didn't even I just click

50:00

I was like, you know

50:02

what? Yeah, I trust Jamie.

50:04

I'll click whatever you said.

50:06

And it was a link

50:08

to HDTP. cat slash like

50:10

200 or slash 404 or

50:12

whatever HDP code and it

50:15

gives you a nice little

50:17

picture of cats doing various

50:19

things with those HDP codes.

50:21

So thank you for not

50:23

fishing me. Yep, I

50:26

clicked it

50:29

so quickly.

50:31

HDP.cat looks

50:34

trustworthy to me,

50:37

I don't know.

50:39

I was gonna

50:41

say, would Chris

50:44

have clicked it

50:47

if it was

50:50

HD.TAC? Oh wait, Christian's giving

50:52

me, oh kick, Jamie, oh okay,

50:54

sorry, no. I mean, you know,

50:56

as long as, you know, if,

50:58

if, if, if, if, if, if

51:00

you need to attack loads in

51:02

safari, then I'll be, I'll, trust

51:04

that it exists. But if it

51:07

gets like a TLD doesn't

51:09

exist, then, I don't know,

51:11

maybe it's something that only

51:13

works on Linux or weird,

51:15

good news distributions distributions

51:18

of things.

51:20

Yeah, not if you not if you brew

51:22

install tack, wait, I should check. Does that

51:25

work? I don't think that works. I think

51:27

you did brew and install for you. Yeah,

51:29

yeah. So if I did like a

51:31

brew info tack, I'm probably gonna get

51:33

like this thing doesn't exist. Which, is

51:35

that a 404 though? Or is it? How much

51:37

research? Yeah, can't find formula type.

51:39

I do think at the end

51:42

of the day, we're talking about

51:44

these status codes. Is like, pick

51:46

something and be consistent and be

51:48

consistent. Like I think that's

51:50

what really matters here, right?

51:52

I've picked something that says

51:54

well. Oh yeah. Sorry, so what with

51:56

the two or four? I put this

51:58

as a on-pop earlier. but I'm

52:00

burning through them. I would

52:03

generally say don't do 204,

52:05

no content because you're just

52:07

going to paint yourself into

52:09

a corner. At some point

52:11

you do actually want to

52:14

return some information.

52:16

So doing an empty Jason object

52:18

with a 200 gives you the

52:20

chance to change your mind in

52:22

the future without having to do

52:25

like a V2 API, which we

52:27

all know is. Chaos. Definitely

52:29

chaos. Is that empty Jason

52:32

body like an array, an

52:34

object? Does it matter? I'd

52:36

say an empty object. Okay.

52:39

Because returning an empty

52:41

array, I dislike APIs that

52:43

do that. Right. Give me

52:46

an object that can then

52:48

be extended with other things.

52:50

Yeah, and usually the delete case is

52:52

usually one thing at a time.

52:54

So, yeah. I mean like the

52:56

stroke counterpoint return the literal string

52:58

no, I'll lower case. Oh God.

53:00

Oh no. Return in an escape

53:02

sequence or something? No. The so

53:04

the spec does point out like

53:06

a place where 204 is useful

53:08

which is like if you do

53:10

a put and then you can

53:13

just send an e tag back that's

53:15

like the e tag value for

53:17

that put and not send anything

53:19

else. So I think there's really

53:21

really if your if your response

53:23

only needs headers to indicate what

53:25

the application should do or what

53:27

the application can do, then I

53:29

think 204 is appropriate because you

53:31

don't need the body. Yeah, I

53:34

think that's valid. It's a success

53:36

and there's no content so you

53:38

don't have to read the body and

53:40

you can look at the headers. That feels

53:42

like a valid scenario. I don't know.

53:45

I'm with Jamie on this one.

53:47

Just avoid 204. Like I've definitely

53:49

run it, ran into issues where

53:51

like you're expecting it and something

53:53

changed. And I don't know. Even if

53:55

your spec doesn't say this

53:57

will always return 204.

54:00

Right, people, like once you start,

54:02

people expect it and they're going

54:04

to handle errors differently. Like they're

54:06

not, yeah, I don't know. I

54:08

don't know. Just handle. This conversation

54:10

has taught me that HTP is

54:12

a very, very interesting protocol that's

54:14

very extensible in many ways. And

54:16

even in the year of our

54:19

Lord 2025, we still have not

54:21

figured out the best way to

54:23

use HCP tools full's potential. And

54:25

it's. Fairly ironic that the primary

54:27

use case for HCTP now no

54:29

longer involves hypertext whatsoever. Oh, yeah.

54:31

Don't open up that kingdom right

54:33

now. Jane, we're going to bring

54:36

you back on to talk about

54:38

that. HTL is very much hypertext.

54:40

Yeah, but they're far more things

54:42

sending Jason than HTL at this

54:44

point. There's a lot of websites

54:46

in the world. There are a

54:48

lot of sites. And you know

54:50

how many? There's a lot. I

54:53

mean, yes. But also, you know,

54:55

Jason should be hypertext. So that's

54:57

Jason's problem, not HDDP's problem. But

54:59

yes. Although, HDMO is more hypermedia

55:01

than hypertext these days. But yes.

55:03

So anyway. I have one question.

55:05

How do you feel about nonstandard

55:07

HDP status codes? Like when we

55:09

use a lot is 49. Like

55:12

not for the actual clients, but

55:14

to know like if the connect

55:16

it's client closed connection It's what

55:18

like engine X uses. I was

55:20

to say isn't that engine X's

55:22

code? Yeah, and we use that

55:24

like if you're if the client

55:26

does like cancel their request will

55:29

return up 49 even though they'll

55:31

never see it but like all

55:33

of our standing and everything gets

55:35

it picks it up I think

55:37

if like if you have a

55:39

kind of I think it's where

55:41

I fall to one like custom

55:43

HDP methods is that if you

55:46

have a constrained enough environment or

55:48

if you like understand like if

55:50

you as a server know that

55:52

your client knows how to properly

55:54

interpret whatever you're gonna send back

55:56

to them I think it's okay.

55:58

I don't think you should just

56:00

send it back as if like

56:03

if you have to assume at

56:05

first that they're just a spec

56:07

compliant HDP client right so they're

56:09

like okay if I you know

56:11

if you send me back this

56:13

400 I'm gonna interpret it in

56:15

the way of the spec and

56:17

then I think if there's something

56:19

else like a header or something

56:22

that has indicated oh I have

56:24

this expanded functionality then I think

56:26

it's fine to you know use

56:28

that expanded functionality that you were

56:30

just told that it has. That's

56:32

what I, yeah, I included that,

56:34

yeah, same. Oh, sorry, I was

56:36

reading, I was reading a shownote.

56:39

As long as the, as long

56:41

as things have indicated that they

56:43

can accept this or they can

56:45

process it, once again, same kind

56:47

of content negotiation problem, but as

56:49

long as either inbound or out

56:51

of bound, it has been negotiated,

56:53

I think it's returning some random

56:56

error codes that... they used internally

56:58

similar to like the engine X

57:00

one and that just like broke

57:02

stuff both because clients didn't understand

57:04

it but I think there were

57:06

also some like intermediate proxies and

57:08

things that also didn't understand the

57:10

status code so everything just blew

57:12

up as a little bit again

57:15

by common denominator try and stick

57:17

to the things that people don't

57:19

even use because yeah that's a

57:21

that's a very valid point unless

57:23

your CDN's also understand all of

57:25

your non-standard status codes it's probably

57:27

a bad idea yeah that's why

57:29

you have to get it behind

57:32

a way that you know that

57:34

the client will understand it and

57:36

we're back to 200 with response

57:38

body that says we're just going

57:40

back to it I have I

57:42

have one more API design thing

57:44

I'd love to talk about and

57:46

that is IDs Right. This part

57:49

of the show is supporter exclusive

57:51

content. So if you want to

57:53

hear what Ian has to say

57:55

about identifiers, I don't know where

57:57

to fall through dot fm slash

57:59

subscribe. But

58:02

with that, let's do some un-pops.

58:04

Who's got some un-pops? Who's got

58:06

some un-pops? Anybody got un-pops? I

58:09

think Jamie has like 30 un-pops.

58:11

Yeah. Jamie has a long list

58:13

of un-pops. So I'm sure it

58:15

was one of the episodes, Angelica,

58:18

shared an un-pop, back-on, go-time RIP,

58:20

where you mentioned about like storing

58:22

a list of un-pops. So that's

58:25

why I have so many prepared

58:27

so many prepared. Because over time

58:29

I have been thinking of them,

58:31

fighting my time. It's funny because

58:34

I'm reading Jamie's Unpops, like the

58:36

list, and the very first one

58:38

is like, won't do them all

58:41

or won't say them all? Yes,

58:43

you will. You're going to say

58:45

them all, don't you worry? How

58:48

dare you? I have one that

58:50

since we're talking about APIs and

58:52

transfer protocols and bodies, XMLs good.

58:54

Is my is my Unpop, Unpop

58:57

or opinion. I know Jason gets

58:59

all the love these days and

59:01

XML with namespaces with all the

59:04

values as the content between the

59:06

elements was admittedly terrible, but XML

59:08

as a document structure, I prefer

59:10

to Jason for no other reason

59:13

than the element names give you

59:15

a hint of what it what

59:17

it is compared to Jason objects

59:20

which are just open brace. dictionary

59:22

of string names to values. I

59:24

mean, what namespace is, excellent, the

59:27

element name tells you exactly what

59:29

it is. And I will say,

59:31

as long as you also use

59:33

attributes where it makes sense, like

59:36

I'm in favor of like namespaces,

59:38

attributes, and if it's a value,

59:40

put the value in. But I

59:43

enjoy that. I like XML. It

59:45

gives you that flexibility. You can

59:47

include multiple different things in there,

59:49

and you know what they mean.

59:52

It's very defined. Unlike Jason, which

59:54

is just a soup of strings.

59:56

We did a lot of work

59:59

in XML in my Windows days

1:00:01

and we were We leaned hard

1:00:03

into attribute-based XML versus element-based and

1:00:05

avoided overly leaning into namespaces because

1:00:08

namespaces are hard to manage. But

1:00:10

we got a lot of mileage

1:00:12

out of XML without dealing with

1:00:15

all the terribleness that was the

1:00:17

soap protocol. Yeah. XML gets a

1:00:19

bad rat because of soap. that

1:00:22

it's like self-describing though. Like I

1:00:24

don't like using rest. Like not

1:00:26

wrong. You like you like the

1:00:28

aspects of it that are like

1:00:31

it tells it it tells it

1:00:33

tells it tells it tells you

1:00:35

about itself which is just nice.

1:00:38

Yeah like like like like a

1:00:40

rest API I have to go

1:00:42

find the open at API spec

1:00:44

and everything like a soap API

1:00:47

I can just request request request

1:00:49

the whistle and I have it.

1:00:51

Is that how you say that,

1:00:54

Whistle, WSTL? Yes, Whistle. Shutter again.

1:00:56

Yeah, I mean, I'll be pedantic.

1:00:58

A properly designed rest API, however,

1:01:01

you would just have a nice

1:01:03

little spec you can go read,

1:01:05

which is basically a whistle. It

1:01:07

could be machine readable if you

1:01:10

want it to be. But you

1:01:12

would have that. And that would

1:01:14

be, that'd be nice. That'd be

1:01:17

nice. But no one designs API

1:01:19

is that way. I tend to

1:01:21

do. kind of the analog for

1:01:23

protobuff APIs, whereas as part of

1:01:26

building the system you can generate

1:01:28

a The file the binary file

1:01:30

descriptor, which is kind of your

1:01:33

compiled API definition Go embed that

1:01:35

into your binary and include an

1:01:37

in point that returns that descriptor.

1:01:39

Yes. Yeah. Oh, that's good. Then

1:01:42

someone can just ask you for

1:01:44

hey, what is your API look

1:01:46

like here? It's Jamie, did you

1:01:49

decide which of these many un-pops

1:01:51

you want to unpop? Yeah, at

1:01:53

the end of January I wrote

1:01:56

a post about... the new go

1:01:58

tool that's coming in, go 124,

1:02:00

that is now out, obviously, because

1:02:02

it's March. We shipped this episode

1:02:05

early, now you're going to sound

1:02:07

weird. Yeah. I was less excited

1:02:09

once writing the post, once I

1:02:12

actually got to play around with

1:02:14

it. And I still posted it

1:02:16

with the positivity, but I think

1:02:18

it's not quite where it should

1:02:21

be. And I think most people

1:02:23

aren't going to use it. And

1:02:25

yeah, I've also seen lots of

1:02:28

angry people on Reddit and Hacker

1:02:30

News who are like, oh, goes

1:02:32

getting so bloated. And who even

1:02:34

asked for this? And it's like,

1:02:37

well, lots of people ask for

1:02:39

it. great. I was excited about

1:02:41

the feature. I've used Tools.go with

1:02:44

a Plus Build None lots of

1:02:46

times to have references to build

1:02:48

tools in go-out mods to make

1:02:51

them straightforward to use. I've used

1:02:53

it a lot so I was

1:02:55

very excited about the idea of

1:02:57

that being built into the tool

1:03:00

chain. Then I went and read

1:03:02

your blog and yes, it's not

1:03:04

quite there. So I haven't read

1:03:07

how it works or your blog

1:03:09

post. What are the issues? So

1:03:11

have you seen like the tools.go

1:03:13

pattern? Yeah yeah yeah yeah. So

1:03:16

one of the key issues with

1:03:18

that is that it then adds

1:03:20

indirect dependencies on all of the,

1:03:23

oh it adds a direct dependency

1:03:25

for the tool that you're requiring

1:03:27

and then pollutes with indirect. with

1:03:30

go to is it literally doesn't.

1:03:32

same thing but there is an

1:03:34

additional directive in your go dot

1:03:36

mod to say and this module

1:03:39

is a tool so you still

1:03:41

have the indirect dependencies that are

1:03:43

polluting everything which yeah I think

1:03:46

the main positive that I'm taken

1:03:48

away from this is the fact

1:03:50

that with go 124 they're now

1:03:52

cashing things that are either through

1:03:55

go tool or through go run

1:03:57

as far as I'm aware so

1:03:59

The idea will be that even

1:04:02

if you're using the old tools.go

1:04:04

you will get a performance boost,

1:04:06

whereas before it would recompile your

1:04:08

go runs each time. So it

1:04:11

will be a bit better. Yeah,

1:04:13

I'm not really a fan of

1:04:15

the idea of having to run

1:04:18

go tool and the name rather

1:04:20

than run the tool itself. So

1:04:22

the pattern with tools.go is you

1:04:25

have the reference in your tools.go

1:04:27

file, then you can go install.

1:04:29

the name of the tool in

1:04:31

Project Durbin because don't go install

1:04:34

into global directories. But then you

1:04:36

can just run the tool in

1:04:38

your build script, air quotes, whatever

1:04:41

the case may be. So I

1:04:43

would disagree that that's the pattern,

1:04:45

and I would see the pattern

1:04:47

as running go run of the

1:04:50

module path, because then it definitely

1:04:52

is 100%. You literally can just

1:04:54

get clone and run like go

1:04:57

generate and then that works However

1:04:59

by installing them ahead of time,

1:05:01

but you get the performance boost

1:05:04

and everything But then you still

1:05:06

have the problem of if you're

1:05:08

go generates then call a binary

1:05:10

How does that binary get installed?

1:05:13

Yeah, I've kind of in recent

1:05:15

times I've moved away from using

1:05:17

go generate for those kind of

1:05:20

things we get bitten pretty hard

1:05:22

when they fixed, air quotes, the

1:05:24

security hole and go generate, where

1:05:26

you could go generate, it would

1:05:29

run. arbitrary command, including things outside

1:05:31

of your working directory and things

1:05:33

that haven't been verified. So it

1:05:36

was a valid security concern, but

1:05:38

we had a lot of go

1:05:40

generate directives that were running local

1:05:42

scripts and local binaries that started

1:05:45

failing. And the other thing that

1:05:47

we kind of ran into is

1:05:49

go generate only accepts a single

1:05:52

command and The particular thing that

1:05:54

bit us hard was running a

1:05:56

script, a tool in another internal

1:05:59

repo, but you want the version,

1:06:01

kind of the same problem I

1:06:03

brought up in the fall-through channel

1:06:05

and slack, where you want the

1:06:08

version of the tool that goes

1:06:10

with the library that you're using.

1:06:12

We, in go-path days, you could

1:06:15

just run go-path source, whatever. If

1:06:17

it's packaged in a module, the

1:06:19

path is in your module cache

1:06:21

and you need to go list

1:06:24

with a minus F to get

1:06:26

the path to the module on

1:06:28

disk in your local module cache

1:06:31

to then get the thing to

1:06:33

run. You can't do that in

1:06:35

a go generate because there's no

1:06:37

bash subshell to go run the

1:06:40

command and get to do two

1:06:42

steps. So we ended up doing

1:06:44

a lot of work to kind

1:06:47

of pull those kind of things.

1:06:49

out of a go generate directive

1:06:51

in the code into you just

1:06:54

a generate make target. All right,

1:06:56

Matt. Oh yeah. Yeah, mine's very

1:06:58

quick. My unpopular opinion is that

1:07:00

you should not use single letter

1:07:03

CLI options in your documentation. So

1:07:05

when you're like writing docs to

1:07:07

show like your CLI usage for

1:07:10

something and everyone just uses a

1:07:12

bunch of single letter CLI options,

1:07:14

don't do that. It's not. Well

1:07:16

documenting now you're just forcing your

1:07:19

users to go look up. the

1:07:21

help text for your CLI to

1:07:23

see what those options even mean,

1:07:26

use the long options if they're

1:07:28

available. 60 years of Unix Man

1:07:30

pages disagree with you. Sure, but

1:07:33

a lot of them haven't even

1:07:35

thought through what those options mean.

1:07:37

Like a lot of people would

1:07:39

just say, oh I'm going to

1:07:42

use dash I to mean pencil.

1:07:44

And it's just like, what? Have

1:07:46

you thought about any of this?

1:07:49

Similar to what we're talking about,

1:07:51

the API design, like, think through

1:07:53

the design of your CLI, too,

1:07:55

and don't just choose an option

1:07:58

because it's convenient for you to

1:08:00

type. Choose an option because it's

1:08:02

semantically meaningful for the CLI design.

1:08:05

And to be honest, when I

1:08:07

saw you starting typing this one,

1:08:09

I thought you were going to

1:08:11

end as, don't use single letter

1:08:14

CLI options, full stop. No, no,

1:08:16

no, no, no, no, no, no,

1:08:18

you should definitely use, you should

1:08:21

definitely use them, but when you

1:08:23

should definitely use them, but when

1:08:25

you're, but when you're, but when

1:08:28

you're documenting, but when you're documenting,

1:08:30

but when you're documenting something, but

1:08:32

when you're documenting something, but when

1:08:34

you're documenting something, but when you're

1:08:37

documenting something, but when you're documenting

1:08:39

something, but when you're documenting something,

1:08:41

but when you're documenting something, but

1:08:44

when you're documenting something, but when

1:08:46

you're use the full options it

1:08:48

helps them like get a picture

1:08:50

of what SCLI is doing. Otherwise

1:08:53

you just you just lose your

1:08:55

reader right like dash i dash

1:08:57

v dash just like nobody knows

1:09:00

what that means image intent ignore

1:09:02

me differ depending on the operating

1:09:04

system I could go hard on

1:09:06

popular and say use slash instead

1:09:09

of minus ill all right windows

1:09:11

over here no no thank you

1:09:13

Okay Dylan that's a that's and

1:09:16

do you have an unpopular opinion?

1:09:18

I do. We're talking about API

1:09:20

design. So for URL parameters it

1:09:23

seems pretty popular to allow like

1:09:25

a comma separated list as like

1:09:27

you know question mark ID equals

1:09:29

one comma two comma three. I

1:09:32

think I prefer like the spec

1:09:34

compliant ID question mark ID equals

1:09:36

one and then a second one

1:09:39

ID equals one ID equals two

1:09:41

ID equals three. Like I think

1:09:43

I prefer that just. It's the

1:09:45

spec also allows plus so that

1:09:48

there are some parches that will

1:09:50

take ID equals one and ID

1:09:52

equals two and percent ID equals

1:09:55

three and we'll turn them into

1:09:57

ID equals one. plus two plus

1:09:59

three. Who does that? I've seen

1:10:02

it a few times. I don't

1:10:04

know. I think I, yeah, I

1:10:06

just prefer not having like, comma

1:10:08

separated lists places. It just gets

1:10:11

a nice fair. I don't want

1:10:13

to put a parser in my.

1:10:15

Exactly. Yeah, I don't want a

1:10:18

second parse step. Just let the

1:10:20

parser do its thing. Got my

1:10:22

query string, now I got a

1:10:24

parse again. Yikes. Okay. All right.

1:10:27

Well, I don't have any. A

1:10:29

lot of people don't even know

1:10:31

you can do that. Like, put

1:10:34

the same value more than once.

1:10:36

Yeah, you can do with headers

1:10:38

as well. For some headers. Some

1:10:40

headers are not allowed to be

1:10:43

specified more than once. Yeah. All

1:10:45

right. Yeah, I think I said

1:10:47

enough on paper. I think this

1:10:50

episode, don't. It's anything more. Or

1:10:52

I can just say, use HDPP

1:10:54

properly. You're all wrong. People should

1:10:57

just learn. And the world will

1:10:59

be able to be able to

1:11:01

replace for it. it would be

1:11:03

fine. It's not even that. It's

1:11:06

like if everybody could just follow

1:11:08

the specification and follow what rest

1:11:10

actually means instead of what someone

1:11:13

just made up and then the

1:11:15

author of rest was like this

1:11:17

is incorrect and everybody was like

1:11:19

but we think it's correct and

1:11:22

it's like okay well that's weird

1:11:24

why are you doing it this

1:11:26

way it doesn't align with the

1:11:29

values of the thing that I

1:11:31

wrote and but everybody's like no

1:11:33

we're gonna steal your name now.

1:11:36

I mean that's well still the

1:11:38

name of the thing you made.

1:11:40

I will pull a skeleton meme

1:11:42

and as we wrap I'll drop

1:11:45

hadios and then leave. No, we're

1:11:47

leaving now. Oh no, oh no.

1:11:49

Just call it the hyper media

1:11:52

constraint. The fact that hadios or

1:11:54

hadios or whatever, hyper media as

1:11:56

the engine of application state, like

1:11:58

you don't know what that means.

1:12:01

You don't know what that means.

1:12:03

You don't know what those words

1:12:05

mean. You don't know what that

1:12:08

sentence means. Stop using it. It

1:12:10

appears exactly once. Maybe. I think

1:12:12

exactly once in the dissertation. But

1:12:14

like hold out. Just call it

1:12:17

the hyperme. media constraint. James shared

1:12:19

a URL. in chat about like

1:12:21

can we please stop saying just

1:12:24

and I was literally having this

1:12:26

conversation with a friend yesterday about

1:12:28

like we hide so much behind

1:12:31

the word just just implement a

1:12:33

no no I'm going on tangent

1:12:35

I don't care I'm tangent just

1:12:37

I'm tangent just just implement the

1:12:40

API just read the code is

1:12:42

the worst one just read the

1:12:44

code no I don't want to

1:12:47

just read your code because your

1:12:49

code is garbage and you don't

1:12:51

have any documentation and you don't

1:12:53

have any documentation to write documentation

1:12:56

for your code I'm not going

1:12:58

to be bothered reading your code.

1:13:00

Because you clearly didn't care about

1:13:03

my time. Why should I care

1:13:05

about your time? And so yeah,

1:13:07

that word just is so frustrating

1:13:09

and it hides so much complexity.

1:13:12

And it's just like, it's an

1:13:14

excuse for not formulating a proper

1:13:16

thought and like documenting what you're

1:13:19

doing. Just do the thing. Just

1:13:21

leave. self-documented code. Yeah. Okay, we

1:13:23

can't go on any more rams.

1:13:26

I know, I know, I'm sorry,

1:13:28

I'm sorry. We're already at two

1:13:30

hours of recording. Yeah, so we

1:13:32

just, we just, you know, Jamie,

1:13:35

where can people find you? Yeah.

1:13:37

Um, JVT.me slash elsewhere is the

1:13:39

best place. It has all of

1:13:42

my links. Um, yeah. Perfect. Perfect.

1:13:44

And with that, viewers, listeners. As

1:13:46

always, please like. Just like and

1:13:48

subscribe. Oh no. Like, comment, share,

1:13:51

subscribe. If you're on YouTube, hit

1:13:53

the little notification bell and reach

1:13:55

out to us on social media.

1:13:58

Do you agree? Should we use

1:14:00

just? Should we not use just?

1:14:02

What you think about all our

1:14:05

opinions about APIs? Are we wrong?

1:14:07

Do you think we're wrong? You

1:14:09

can reach out or you can

1:14:11

send us a letter once again.

1:14:14

I think by the point this

1:14:16

episode ships, everybody will know what

1:14:18

the PO box is. So just

1:14:21

that does some things, that does

1:14:23

some letters, some nice things. Just,

1:14:25

oh my goodness. Okay, we're done.

1:14:27

Tagline, it's what we do. Yeah.

1:14:30

Uh, thank you so much Jamie

1:14:32

for coming on. Thanks on me.

1:14:34

Yeah, it's been a pleasure. Yeah,

1:14:37

thank you. Bye everybody. Bye. Take

1:14:39

the button. Click the button. Click

1:14:41

the button. Just certified mail, please.

1:14:43

I'm sorry. You said the button.

1:14:46

I'm sorry. Just click the button.

1:14:48

I'm sorry. Just click the button.

1:14:50

Okay. Okay. Okay. The button. On

1:14:53

next week's episode, we have Kelsey

1:14:55

Hightower joining us to talk about

1:14:57

go, AI, Devrel, and so much

1:15:00

more. You really don't want to

1:15:02

miss that episode. This episode of

1:15:04

Fall Through was hosted by Chris

1:15:06

Brando, with co-host Matthew Snobria, Ian

1:15:09

Wester Lopshire, and Dylan Burke. Our

1:15:11

guest this week was Jamie Tana.

1:15:13

Author is produced by Chris Brando

1:15:16

and Angelica Hill, and our beats

1:15:18

are by Breakmaster Cylinder. Somebody

1:15:29

that I used to

1:15:31

go.

Rate

Join Podchaser to...

  • Rate podcasts and episodes
  • Follow podcasts and creators
  • Create podcast and episode lists
  • & much more

Episode Tags

Do you host or manage this podcast?
Claim and edit this page to your liking.
,

Unlock more with Podchaser Pro

  • Audience Insights
  • Contact Information
  • Demographics
  • Charts
  • Sponsor History
  • and More!
Pro Features