Repository: lnbits/lnbits

Issue:
LNURLw "Get a withdraw link" api call returns html page with error "'WithdrawLink' object is not a mapping"
Hallo, Im playing with lnbits on https://legend.lnbits.com but I can't get "Get a withdraw link" api call to work (other api calls seems to work as expected).

For example "list withdraw links" api call works OK - like this (empty wallet used to report this = keys can be published):
```
curl -X GET https://legend.lnbits.com/withdraw/api/v1/links -H "X-Api-Key: 17fdca9435dc4645b2690b934cc52b3c" 
[{"id":"V82kpyfsQtzUBknfL4fbqW","wallet":"23036b3a10d64eb19eeddb0d55ee2a29","title":"test23","min_withdrawable":10,"max_withdrawable":10,"uses":1,"wait_time":1,"is_unique":false,"unique_hash":"DJTEARWUG6do7hytqmnyLS","k1":"KwmSzwXNzFHAVjBCZRqWVi","open_time":1649194725,"used":0,"usescsv":"1","number":0,"lnurl":"LNURL1DP68GURN8GHJ7MR9VAJKUEPWD3HXY6T5WVHXXMMD9AMKJARGV3EXZAE0V9CXJTMKXYHKCMN4WFKZ73Z223Z5Z5JH24RNVER0XA58JAR3D4H8JNZNGA087U"}]
```

but when trying to call "Get a withdraw link":
```
curl -X GET https://legend.lnbits.com/withdraw/api/v1/links/V82kpyfsQtzUBknfL4fbqW -H "X-Api-Key: 17fdca9435dc4645b2690b934cc52b3c" 
<!DOCTYPE html>

<html lang="en">
  <head>
    
    <link rel="stylesheet" type="text/css" href="/static/vendor/quasar@1.13.2/quasar.min.css" />
    
    <link rel="stylesheet" type="text/css" href="/static/vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.css" />
    
    <link rel="stylesheet" type="text/css" href="/static/vendor/chart.js@2.9.3/chart.min.css" />
    
    <!---->
    <link rel="stylesheet" type="text/css" href="/static/css/base.css" />

    
    <title>LNbits</title>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    
  </head>

  <body data-theme="bitcoin">
    <q-layout id="vue" view="hHh lpR lfr" v-cloak>
      <q-header bordered class="bg-marginal-bg">
        <q-toolbar>
          
          <q-toolbar-title>
            <q-btn flat no-caps dense size="lg" type="a" href="/">
              
<a href="/" class="inherit">
  
  <strong>LN</strong>bits 
</a>
</q-btn
            >
          </q-toolbar-title>
          
          <q-btn-dropdown
            v-if="g.allowedThemes && g.allowedThemes.length > 1"
            dense
            flat
            round
            size="sm"
            icon="dashboard_customize"
            class="q-pl-md"
          >
            <div class="row no-wrap q-pa-md">
              <q-btn
                v-if="g.allowedThemes.includes('classic')"
                dense
                flat
                @click="changeColor('classic')"
                icon="format_color_fill"
                color="deep-purple"
                size="md"
                ><q-tooltip>classic</q-tooltip>
              </q-btn>
              <q-btn
                v-if="g.allowedThemes.includes('bitcoin')"
                dense
                flat
                @click="changeColor('bitcoin')"
                icon="format_color_fill"
                color="orange"
                size="md"
                ><q-tooltip>bitcoin</q-tooltip>
              </q-btn>
              <q-btn
                v-if="g.allowedThemes.includes('mint')"
                dense
                flat
                @click="changeColor('mint')"
                icon="format_color_fill"
                color="green"
                size="md"
                ><q-tooltip>mint</q-tooltip> </q-btn
              ><q-btn
                v-if="g.allowedThemes.includes('autumn')"
                dense
                flat
                @click="changeColor('autumn')"
                icon="format_color_fill"
                color="brown"
                size="md"
                ><q-tooltip>autumn</q-tooltip>
              </q-btn>
              <q-btn
                v-if="g.allowedThemes.includes('monochrome')"
                dense
                flat
                @click="changeColor('monochrome')"
                icon="format_color_fill"
                color="grey"
                size="md"
                ><q-tooltip>monochrome</q-tooltip>
              </q-btn>
              <q-btn
                v-if="g.allowedThemes.includes('salvador')"
                dense
                flat
                @click="changeColor('salvador')"
                icon="format_color_fill"
                color="blue-10"
                size="md"
                ><q-tooltip>elSalvador</q-tooltip>
              </q-btn>
              <q-btn
                v-if="g.allowedThemes.includes('flamingo')"
                dense
                flat
                @click="changeColor('flamingo')"
                icon="format_color_fill"
                color="pink-3"
                size="md"
                ><q-tooltip>flamingo</q-tooltip>
              </q-btn>
            </div>
          </q-btn-dropdown>

          <q-btn
            dense
            flat
            round
            @click="toggleDarkMode"
            :icon="($q.dark.isActive) ? 'brightness_3' : 'wb_sunny'"
            size="sm"
          >
            <q-tooltip>Toggle Dark Mode</q-tooltip>
          </q-btn>
        </q-toolbar>
      </q-header>

       
      <q-page-container>
        <q-page class="q-px-md q-py-lg" :class="{'q-px-lg': $q.screen.gt.xs}">
          
<div class="row q-col-gutter-md justify-center">
  <div class="col-12 col-md-7 col-lg-6 q-gutter-y-md">
    <q-card class="q-pa-lg">
      <q-card-section class="q-pa-none">
        <center>
          <h3 class="q-my-none">Error</h3>
          <br />
          <q-icon
            name="warning"
            class="text-grey"
            style="font-size: 20rem"
          ></q-icon>

          <h5 class="q-my-none">&#39;WithdrawLink&#39; object is not a mapping</h5>
          <h4>If you believe this shouldn't be an error please bring it up on https://t.me/lnbits</h4>
          <br />
        </center>
      </q-card-section>
    </q-card>
  </div>

  
        </q-page>
      </q-page-container>
       

      <q-footer
        class="bg-transparent q-px-lg q-py-md"
        :class="{'text-dark': !$q.dark.isActive}"
      >
        <q-toolbar class="gt-sm">
          <q-toolbar-title class="text-caption">
            LNbits, free and open-source lightning wallet
            <br />

            <small v-if="'LNbits' == 'LNbits'"
              >Commit version: 2f381960a07d62e5da16e721bedd77e881095b82</small
            >
          </q-toolbar-title>
          <q-space></q-space>
          <q-btn
            flat
            dense
            :color="($q.dark.isActive) ? 'white' : 'primary'"
            icon="code"
            type="a"
            href="https://github.com/lnbits/lnbits"
            target="_blank"
            rel="noopener"
          >
            <q-tooltip>View project in GitHub</q-tooltip>
          </q-btn>
        </q-toolbar>
      </q-footer>

      
    </q-layout>

    
    <!---->
    
    <script src="/static/vendor/moment@2.27.0/moment.min.js"></script>
    
    <script src="/static/vendor/vue@2.6.12/vue.js"></script>
    
    <script src="/static/vendor/vue-router@3.4.3/vue-router.js"></script>
    
    <script src="/static/vendor/quasar@1.13.2/quasar.ie.polyfills.umd.min.js"></script>
    
    <script src="/static/vendor/axios@0.20.0/axios.min.js"></script>
    
    <script src="/static/vendor/bolt11/decoder.js"></script>
    
    <script src="/static/vendor/chart.js@2.9.3/chart.min.js"></script>
    
    <script src="/static/vendor/quasar@1.13.2/quasar.umd.js"></script>
    
    <script src="/static/vendor/underscore@1.10.2/underscore.min.js"></script>
    
    <script src="/static/vendor/vue-qrcode-reader@2.2.0/vue-qrcode-reader.min.js"></script>
    
    <script src="/static/vendor/vue-qrcode@1.0.2/vue-qrcode.min.js"></script>
    
    <script src="/static/vendor/vuex@3.5.1/vuex.js"></script>
    
    <!---->
    <script src="/static/js/base.js"></script>
    <script src="/static/js/components.js"></script>
    <script type="text/javascript">
      const themes = ["bitcoin", " mint", " flamingo", " classic", " autumn", " monochrome", " salvador"]
      const LNBITS_DENOMINATION = "sats"
      console.log(LNBITS_DENOMINATION)
      if(themes && themes.length) {
        window.allowedThemes = themes.map(str => str.trim())
      }
    </script>
    

  <script>
    new Vue({
      el: '#vue',
      mixins: [windowMixin],
      data: function () {
        return {}
      }
    })
  </script>

  
  </body>
</html>
```
...when this html is saved to file and opened in browser, I get an error message "'WithdrawLink' object is not a mapping":
![obrazek](https://user-images.githubusercontent.com/26651175/161861168-7d7bb0b0-5fa1-44f2-9091-a75ec9dd586a.png)

when nonexistent withdraw_id is used in the call the reponse seems to be correct:
```
curl -X GET https://legend.lnbits.com/withdraw/api/v1/links/123456789 -H "X-Api-Key: 17fdca9435dc4645b2690b934cc52b3c" 
{"detail":"Withdraw link does not exist."}
```
Is this a bug or am I doing sth wrong?

Thank you.


Discussion:

Resolving patch:
diff --git a/lnbits/extensions/withdraw/views_api.py b/lnbits/extensions/withdraw/views_api.py
--- a/lnbits/extensions/withdraw/views_api.py
+++ b/lnbits/extensions/withdraw/views_api.py
@@ -60,7 +60,7 @@ async def api_link_retrieve(
         raise HTTPException(
             detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN
         )
-    return {**link, **{"lnurl": link.lnurl(request)}}
+    return {**link.dict(), **{"lnurl": link.lnurl(request)}}
 
 
 @withdraw_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)


Test patch: