HTTP 200 vs 400 from stations api

Skip to first unread message

Feb 19, 2024, 2:00:22 PMFeb 19
to weewx-development
I was in the process of updating to log the returned error message. If you want the stations api to return a 400, you could do something like this.

def test_post():
    url = 'http://localhost:5000/api/v2/stations/'

    body = {
        'station_url': '',
    json_body = json.dumps(body)

    request = urllib.request.Request(url)
    request.add_header('Content-Type', 'application/json')

        response = urllib.request.urlopen(request, data=json_body.encode('utf-8'))
    except urllib.error.HTTPError as http_error:
        raw_data =
        error_msg = raw_data.decode()

I’m still trying to understand any edge cases/nuances, so the 200 is probably a bit ‘safer’.

Tom Keffer

Feb 19, 2024, 2:21:32 PMFeb 19
to, weewx-development
The problem is that urllib.request.urlopen() raises an exception if it gets an HTTP error code 400. That makes the response body totally unavailable.

I studied the HTTP error codes and decided that code 200 means that the HTTP transmission was successful. It does not necessarily mean that the application-level transaction was successful, i.e., the resource (in this case, a station registration) was created. So, a 200 code can be sent back even if the registration failed.

By contrast, 400 means that the client malformed the request badly enough that the server is unable to process it. Presumably, at all. 

So, I switched from 400 to 200 so that we can send some details to the client on why a registration could not be processed.

But, the documentation I read was never crystal clear on what to do when a client passed on invalid data.

Caveat: I am not an expert on this! Everything above comes from an hour or two of research on the topic --- the sum total of my expertise!

Thanks for taking a look at this, Rich!


You received this message because you are subscribed to the Google Groups "weewx-development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
To view this discussion on the web visit

Feb 19, 2024, 2:33:43 PMFeb 19
to weewx-development
Oh the arguments/debates we had on what response code to use. It is a grey area…
My example code does read the response body on that exception. It appears you can either use the read() method on the exception or the fp attribute.

exception urllib.error.HTTPError(urlcodemsghdrsfp)

Though being an exception (a subclass of URLError), an HTTPError can also function as a non-exceptional file-like return value (the same thing that urlopen() returns). This is useful when handling exotic HTTP errors, such as requests for authentication.

You have something working, its not worth changing. 


Ps. Flask looks pretty cool. Got the stations api running in dev mode in minutes.

Feb 19, 2024, 2:37:18 PMFeb 19
to weewx-development

Mumble, grumble… fp seems to added in python 3.12. Or at least that is the place it is documented.
If you wanted to pursue, I could test on other versions.
But what you ain’t broke….

Tom Keffer

Feb 19, 2024, 2:58:26 PMFeb 19
to, weewx-development
I'm happy with what we have because it also works on older versions of WeeWX. If we start probing the exception, that would only work on new code.

Feb 19, 2024, 4:19:06 PMFeb 19
to weewx-development
Makes sense.

Feb 19, 2024, 4:21:19 PMFeb 19
to weewx-development
FYI, it all seems to work with python 3.6 - in case some stumbles onto this thread and is extending the class to interact with a service that does return a 400.
Reply all
Reply to author
0 new messages