Search code examples
restpostmanavro

How to send http post request with an Avro file?


I have a flask api that is expecting a post request in Avro. The problem is I'm not sure how to send Avro requests to test it. The api reads the data using the fastavro.reader(io.BytesIO(request.data))

I have tried using postman: In the header defining Content-Type as "avro/binary" However looks like its not possible https://github.com/postmanlabs/postman-app-support/issues/4435

I also tried curl:

curl -X POST -H "Content-Type: avro/binary" --data "{"city": "ALA",
"number_of_points": 42, "transport": "CAR", "subtype": "PURCHASE"}"
"http://localhost:8080/invocations"

However fastavro returns the following error:

File "fastavro/_read.pyx", line 725, in fastavro._read.file_reader.init

ValueError: cannot read header - is it an avro file?

Resources:

https://github.com/fastavro/fastavro

https://avro.apache.org/


Solution

  • Okay, so I am assuming you have a valid .avro file, as per the example on the fastavro docs.

    This then becomes a simple case of handling this as a standard file upload to Flask. So rather than taking the data from request.data you could so something like:

    from fastavro import reader
    from flask import Flask, request
    app = Flask(__name__)
    
    # This is really basic and could use some validation
    @app.route('/invocations', methods=['POST'])
    def upload():
        if request.method == 'POST':
            file = request.files['file']
            for record in reader(file):
                    print (record)
            return 'uploaded'
    

    You could then submit your file to the endpoint with curl:

    curl -i -X POST -F '[email protected]' "http://localhost:5000/invocations" -H 'ContentType: multipart/form-data'
    

    This should result in something on the server console like:

     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    {'station': '011990-99999', 'time': 1433269388, 'temp': 0}
    {'station': '011990-99999', 'time': 1433270389, 'temp': 22}
    

    If you wish to submit using the requests library, you can do something like this:

    import requests
    
    def upload(filename):
        headers={'ContentType': 'multipart/form-data'}
        with open(filename,'rb') as f:
            files = {'file': f}
            url='http://localhost:5000/invocations'
            r = requests.post(url, files=files)
            print (r.content, r.status_code)
    
    upload('out.avro')