Show description or comments for variables in FastAPI autodocs (Swagger UI) - swagger-ui

I'm making a function and class for it with POST method.
Since I use FastAPI, it automatically generates API docs (using OpenAPI specification and Swagger UI), where I can see the function's description or example data there.
My class and function are like below:
from pydantic import BaseModel, Field
from typing import Optional, List
#app.post("/user/item")
def func1(args1: User, args2: Item):
...
class User(BaseModel):
name: str
state: List[str]
class Config:
schema_extra = {
"example": {
"name": "Mike",
"state": ["Texas", "Arizona"]
}
}
class Item(BaseModel):
_id: int = Field(..., example=3, description="item id")
Through schema_extra and example attribute in Field, I can see the example value in Request body of function description.
It shows like
{
"args1": {
"name": "Mike",
"state": ["Texas", "Arizona"] # state user visits. <-- I'd like to add this here or in other place.
},
"args2: {
"_id": 3 <-- Here I can't description 'item id'
}
}
However, I'd like to add description or comments to example value, like # state user visits above.
I've tried to add description attribute of pydantic Field, but I think it shows only for parameters of get method.
Is there any way to do this? Any help will be appreciated.

You are trying to pass "comments" inside the actual JSON payload that will be sent to the server. Thus, such an approach wouldn't work. The way to add description to the fields is as shown below. Users/you can see the descriptions/comments, as well as the examples provided, by expanding the corresponding JSON schema of a Pydantic model (e.g., "User") under "Schemas" (at the bottom of the page) when visting OpenAPI at http://127.0.0.1:8000/docs, for instance. Or, by clicking on "Schema", next to "Example Value", above the example given in the "Request Body".
class User(BaseModel):
name: str = Field(..., description="Add user name")
state: List[str] = Field(..., description="State user visits")
class Config:
schema_extra = {
"example": {
"name": "Mike",
"state": ["Texas", "Arizona"]
}
}
Alternatively, you could use Body field in your endpoint, allowing you to add a description that is shown under the example in the "Request body". As per the documentation:
But when you use example or examples with any of the other utilities
(Query(), Body(), etc.) those examples are not added to the JSON
Schema that describes that data (not even to OpenAPI's own version of
JSON Schema), they are added directly to the path operation
declaration in OpenAPI (outside the parts of OpenAPI that use JSON
Schema).
You could add multiple examples (with their associated descriptions), as described in the documentation. Example below:
#app.post("/user/item")
async def update_item(
user: User = Body(
...,
examples={
"normal": {
"summary": "A normal example",
"description": "**name**: Add user name. **state**: State user vistis. ",
"value": {
"name": "Mike",
"state": ["Texas", "Arizona"]
},
}
}
),
):
return {"user": user}

Related

Can't place GraphQL custom type as a Postman variable

Has anyone had luck with placing a GraphQL custom type argument as a Postman or Graphql variable? I'm kinda spinning in circles right now, I hope a fresh pair of eyes could point me in the right direction.
What I'm trying to do is to send a mutation request using Postman. The problem I'm having is that the method I'm calling is taking a custom type as an argument. Placing the content of that variable as GraphQL variable or Postman variable is giving me a headache. I can't embedd pictures yet, so here are the links (they are safe).
Schema
This custom type is a JSON-like structure, consisting of two enums and a set of primitive types (strings, ints...). I can screenshot the entire thing but basically that's it: two enums followed by strings, ints...
Custom type definition
What I've tried so far:
Simply hardcoding the request in Postman works but I wish to send multiple requests with varying data
Placing it in a GraphQL variable results in error message
{
"errors": [
{
"message": "Bad request - invalid request body.",
"locations": []
}
],
"data": null
}
Placing the custom type content as a Postman environment variable works, but I'm getting a syntax error (although the request passes...).
Request body is below. Hardcoding it and using a Postman variable produces the same request body, apart from the syntax error.
query: "mutation {
createApplication(request: {
applicationKind: NEW_ISSUANCE,
documentKind: REGULAR_PASSPORT,
personalData: {
timestamp: null,
firstname: "NAME",
lastname: "LASTNAME",
middlename: "MIDDLENAME",
dateOfBirth: "2011-09-28",
citizenshipCountryCode: "USA",
gender: MALE,
personalNumber: "3344",
placeOfBirth: "CHICAGO",
municipalityOfBirth: "SOUTH",
countryCodeOfBirth: "USA"},
addressData:{
street: "WEST",
municipality: "EAST",
place: "CHICAGO",
country: {
code: "USA",
name: null
},
entrance: "б",
flat: "13",
number: "35"}
})
{
__typename
... on AsyncTaskStatus {
taskID
state
payload {
... on ApplicationUpdated {
applicationID
applicationNumber
__typename
}
__typename
}
__typename
}
... on Error {
...errorData
__typename
}
}
}
fragment errorData on Error {
__typename
code
message
}"
Postman variable with a squiggly line
I'm spinning in circles right now. Has anyone had any luck with Postman requests of this kind?
I can post more info, screenshots...just let me know. I'll be watching this topic closely and provide feedback.
Thank you for your time.
please add a the variable in variable section as :
{
"request": {{request}}
}
and then refer this in your query as
$request

How to get a sub-field of a struct type map, in the search response of YQL query in Vespa?

Sample Data:
"fields": {
"key1":0,
"key2":"no",
"Lang": {
"en": {
"firstName": "Vikrant",
"lastName":"Thakur"
},
"ch": {
"firstName": "维克兰特",
"lastName":"塔库尔"
}
}
}
Expected Response:
"fields": {
"Lang": {
"en": {
"firstName": "Vikrant",
"lastName":"Thakur"
}
}
}
I have added the following in my search-definition demo.sd:
struct lang {
field firstName type string {}
field lastName type string {}
}
field Lang type map <string, lang> {
indexing: summary
struct-field key {
indexing: summary | index | attribute
}
}
I want to write a yql query something like this (This doesn't work):
http://localhost:8080/search/?yql=select Lang.en from sources demo where key2 contains 'no';
My temporary workaround approach
I have implemented a custom searcher in MySearcher.java, through which I am able to extract the required sub-field and set a new field 'defaultLang', and remove the 'Lang' field. The response generated by the searcher:
"fields": {
"defaultLang": {
"firstName": "Vikrant",
"lastName":"Thakur"
}
}
I have written the following in MySearcher.java:
for (Hit hit: result.hits()) {
String language = "en"; //temporarily hard-coded
StructuredData Lang = (StructuredData) hit.getField("Lang");
Inspector o = Lang.inspect();
for (int j=0;j<o.entryCount();j++){
if (o.entry(j).field("key").asString("").equals(language)){
SlimeAdapter value = (SlimeAdapter) o.entry(j).field("value");
hit.setField("defaultLang",value);
break;
}
}
hit.removeField("Lang");
}
Edit-1: A more efficient way instead is to make use of the Inspectable interface and Inspector, like above (Thanks to #Jo Kristian Bergum)
But, in the above code, I am having to loop through all the languages to filter out the required one. I want to avoid this O(n) time-complexity and make use of the map structure to access it in O(1). (Because the languages may increase to 1000, and this would be done for each hit.)
All this is due to the StructuredData data type I am getting in the results. StructureData doesn't keep the Map Structure and rather gives an array of JSON like:
[{
"key": "en",
"value": {
"firstName": "Vikrant",
"lastName": "Thakur"
}
}, {
"key": "ch",
"value": {
"firstName": "维克兰特",
"lastName": "塔库尔"
}
}]
Please, suggest a better approach altogether, or any help with my current one. Both are appreciated.
The YQL sample query I guess is to illustrate what you want as that syntax is not valid. Picking a given key from the field Lang of type map can be done as you do in your searcher but deserializing into JSON and parsing the JSON is probably inefficient as StructuredData implements the Inspectable interface and you can inspect it directly without the need to go through JSON format. See https://docs.vespa.ai/documentation/reference/inspecting-structured-data.html

query params dependent on other query params in hapi-swagger

I am building a hapi-swagger interface to my api. One of the query params, type, has another query param subtype that depends on the former. I have figured out how to implement Joi validation for it successfully but am not so successful with the interface. My validation code is
{
type: Joi.string()
.valid('image', 'publication', 'dataset')
.optional(),
subtype: Joi.string()
.optional()
.when('type', {is: 'image', then: Joi.valid('png', 'jpg')})
.when('type', {is: 'publication', then: Joi.valid('newspaper', 'book')})
.description('subtype based on the file_type')
}
But the interface shows only png and jpg for subtype. Suggestions on how I could implement this so the correct subtype shows when the respective type is chosen?
I tried something similar and it works fine for me. Please checkout my code below:
Joi.object().keys({
billFormat: Joi.string().valid('sms', 'email').required(),
email: Joi.string()
.when('ebillFormat', { is: 'sms', then: Joi.valid('a', 'b') })
.when('ebillFormat', { is: 'email', then: Joi.valid('c', 'd') }),
});
And my payload looks like below:
{
"ebillFormat": "email",
"email": "hello"
}
The error I get is as follows:
{
"statusCode": 400,
"error": "Bad Request",
"message": "child \"email\" fails because [\"email\" must be one of [c, d]]",
"validation": {
"source": "payload",
"keys": [
"email"
]
}
}
Please let me know what exactly you are trying to achieve and what issue are you facing.

Docusign Not Generating Multiple Embedded Recipient Views

I am using the Docusign Rest API, through a gem for Rails. I have 2 recipients, and need both of them to sign the document.
It should work like this:
Generate envelope with borrower(s) info passing to the envelope.
Display embedded document for signing.
Return to custom url/action
If there is another signer, it should
reload the iframe
ask for second signers signature, with the same template that was just signed
Instead it breaks when I reloads the iframe for the 2nd signer. It generates the envelope, with my second signer with its unique ID, email etc. However when I then create the recipient view, it returns nil.
How do I get signer 1 to sign, then load it for the second signer right after, with all the custom fields filled both times?
def deliver(signing_borrower)
client = DocusignRest::Client.new
hashData = {
status: 'sent',
template_id: my_id
signers: [
{
embedded: true,
name: signing_borrower.name,
email: signing_borrower_email,
role_name: if (signing_borrower==borrower) then 'Borrower' else 'Co-borrower' end
}
]
}
generate_liabilities
hashData[:signers][0][:tabs] = if (signing_borrower==borrower) then custom_fields else co_borrower_custom_fields end
#if there is a coborrower, add that data to the form as the second signer
if co_borrower
if signing_borrower==co_borrower then opposite_of_signing_borrower = borrower else opposite_of_signing_borrower = co_borrower end
borrower2= {
name: opposite_of_signing_borrower.name,
email: signing_borrower_email(opposite_of_signing_borrower),
role_name: if (opposite_of_signing_borrower==co_borrower) then 'Co-borrower' else 'Borrower' end
}
#add second borrower to hash to generate envelope with all form fields filled
hashData[:signers] << borrower2
hashData[:signers][1][:tabs] = {
textTabs: text_tabs,
checkboxTabs: checkbox_tabs
}
end
response = client.create_envelope_from_template hashData
self.envelope_id = response["envelopeId"]
self.signing_url = DocusignRest::Client.new.get_recipient_view({
envelope_id: self.envelope_id,
name: signing_borrower.name,
email: signing_borrower_email(signing_borrower),
return_url: return_url
})
response
end
The hashData
{:status=>"sent",
:email=>
{:subject=>"Application...",
:body=>"please sign...."},
:template_id=>"XXXX-XXXX-XXXX",
:signers=>
[{:embedded=>true,
:name=>"DAVID L. TESTCASE",
:email=>"email#test.com",
:role_name=>"Borrower",
:tabs=>
{:textTabs=>
[{:tablabel=>"phone",
:name=>"phone",
:value=>"717-717-7171"}]
}
},
{:name=>"MARISOL TESTCASE",
:email=>"email2#test.com",
:role_name=>"Co-borrower",
:tabs=>
{:textTabs=>
[{:tablabel=>"phone",
:name=>"phone",
:value=>"717-717-7171"}]
}
}]}
You can accomplish what you're trying to do by making 3 API calls:
Create Envelope request, specifying both recipients as 'embedded/captive' by setting clientUserId property for each recipient.
POST Recipient View request to get the URL to launch the first signer's signing session.
POST Recipient View request to get the URL to launch the second signer's signing session.
Here's example JSON for those three calls.
1 - Create Envelope Request
POST https://{{env}}.docusign.net/restapi/{{version}}/accounts/{{acctId}}/envelopes
{
"emailSubject": "Please sign this",
"emailBlurb": "Please sign...thanks!",
"templateId": "064A7973-B7C1-41F3-A2AD-923CE8889333",
"status": "sent",
"templateRoles": [
{
"roleName": "Borrower",
"name": "John Doe",
"email": "johnsemail#outlook.com",
"recipientId": "1",
"clientUserId": "123",
"tabs":{
"textTabs":[
{
"tabLabel":"BorrowerPhone",
"value":"717-717-7171"
},
],
}
},
{
"roleName": "Co-borrower",
"name": "Jane Doe",
"email": "janesemail#outlook.com",
"recipientId": "2",
"clientUserId": "567",
"tabs":{
"textTabs":[
{
"tabLabel":"Co-borrowerPhone",
"value":"717-717-7171"
},
],
}
}
]
}
A successful response will contain the Id of the newly created Envelope.
2 - POST Recipient View (for the First Recipient)
Make this call when the first signer is ready to sign. In the request URL, {{envelopeId}} is the Envelope Id value that was returned in the response of the Create Envelope request, and information in the request body corresponds to info you submitted for the first recipient in the Create Envelope request.
POST https://{{env}}.docusign.net/restapi/{{version}}/accounts/{{acctId}}/envelopes/{{envelopeId}}/views/recipient
{
"authenticationMethod": "Email",
"clientUserId": "123",
"userName": "John Doe",
"email": "johnsemail#outlook.com",
"returnUrl": "http://www.google.com"
}
The response will contain the URL that can be used to launch the DocuSign Envelope for the first recipient.
3 - POST Recipient View (for the Second Recipient)
Make this call when it's time for the second signer to sign. In the request URL, {{envelopeId}} is the Envelope Id value that was returned in the response of the Create Envelope request, and information in the request corresponds to info you submitted for the second recipient in the Create Envelope request.
POST https://{{env}}.docusign.net/restapi/{{version}}/accounts/{{acctId}}/envelopes/{{envelopeId}}/views/recipient
{
"authenticationMethod": "Email",
"clientUserId": "567",
"userName": "Jane Doe",
"email": "janesemail#outlook.com",
"returnUrl": "http://www.google.com"
}
The response will contain the URL that can be used to launch the DocuSign Envelope for the second recipient.
I think the problem is in the JSON request body that you're building. I'm curious where you added the embedded => true property from, that's not in the API docs or examples. As far as I know that is not a valid property, but I think the DocuSign API is forgiving in that it doesn't error out when non-recognized properties are sent, it ignores them instead.
In general, when you are creating Embedded (aka "Captive") recipients you need to configure at least 3 properties for these recipients:
1. email
2. name
3. clientUserId
All of these are client configurable (i.e. you can set them to whatever you want), however whatever values you use when adding each recipient.. you need to reference the same exact values when requesting a signing URL for them.
For example, to add two embedded recipients you can send the following (partial) request body:
"signers": [
{
"name": "Sally Doe",
"email": "test_1#email.com"
"clientUserId": "1000"
},
{
"name": "John Doe",
"email": "test_2#email.com"
"clientUserId": "1001"
}
]
If you do not specify the routingOrder for your recipients then it will default to routing order = 1. And if you don't specify a recipientId, the system will generate a unique GUID for each and assign to them.
Once your envelope has been created and your recipients have been added to it, you can then request the signing URLs, but as mentioned you'll need to reference the same values for name, email, and clientUserId.
For more info you can check out the page on Embedding functionality at the DocuSign Developer Center:
http://www.docusign.com/developer-center/explore/features

How to make elasticsearch add the timestamp field to every document in all indices?

Elasticsearch experts,
I have been unable to find a simple way to just tell ElasticSearch to insert the _timestamp field for all the documents that are added in all the indices (and all document types).
I see an example for specific types:
http://www.elasticsearch.org/guide/reference/mapping/timestamp-field/
and also see an example for all indices for a specific type (using _all):
http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/
but I am unable to find any documentation on adding it by default for all documents that get added irrespective of the index and type.
Elasticsearch used to support automatically adding timestamps to documents being indexed, but deprecated this feature in 2.0.0
From the version 5.5 documentation:
The _timestamp and _ttl fields were deprecated and are now removed. As a replacement for _timestamp, you should populate a regular date field with the current timestamp on application side.
You can do this by providing it when creating your index.
$curl -XPOST localhost:9200/test -d '{
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"_default_":{
"_timestamp" : {
"enabled" : true,
"store" : true
}
}
}
}'
That will then automatically create a _timestamp for all stuff that you put in the index.
Then after indexing something when requesting the _timestamp field it will be returned.
Adding another way to get indexing timestamp. Hope this may help someone.
Ingest pipeline can be used to add timestamp when document is indexed. Here, is a sample example:
PUT _ingest/pipeline/indexed_at
{
"description": "Adds indexed_at timestamp to documents",
"processors": [
{
"set": {
"field": "_source.indexed_at",
"value": "{{_ingest.timestamp}}"
}
}
]
}
Earlier, elastic search was using named-pipelines because of which 'pipeline' param needs to be specified in the elastic search endpoint which is used to write/index documents. (Ref: link) This was bit troublesome as you would need to make changes in endpoints on application side.
With Elastic search version >= 6.5, you can now specify a default pipeline for an index using index.default_pipeline settings. (Refer link for details)
Here is the to set default pipeline:
PUT ms-test/_settings
{
"index.default_pipeline": "indexed_at"
}
I haven't tried out yet, as didn't upgraded to ES 6.5, but above command should work.
You can make use of default index pipelines, leverage the script processor, and thus emulate the auto_now_add functionality you may know from Django and DEFAULT GETDATE() from SQL.
The process of adding a default yyyy-MM-dd HH:mm:ss date goes like this:
1. Create the pipeline and specify which indices it'll be allowed to run on:
PUT _ingest/pipeline/auto_now_add
{
"description": "Assigns the current date if not yet present and if the index name is whitelisted",
"processors": [
{
"script": {
"source": """
// skip if not whitelisted
if (![ "myindex",
"logs-index",
"..."
].contains(ctx['_index'])) { return; }
// don't overwrite if present
if (ctx['created_at'] != null) { return; }
ctx['created_at'] = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
"""
}
}
]
}
Side note: the ingest processor's Painless script context is documented here.
2. Update the default_pipeline setting in all of your indices:
PUT _all/_settings
{
"index": {
"default_pipeline": "auto_now_add"
}
}
Side note: you can restrict the target indices using the multi-target syntax:
PUT myindex,logs-2021-*/_settings?allow_no_indices=true
{
"index": {
"default_pipeline": "auto_now_add"
}
}
3. Ingest a document to one of the configured indices:
PUT myindex/_doc/1
{
"abc": "def"
}
4. Verify that the date string has been added:
GET myindex/_search
An example for ElasticSearch 6.6.2 in Python 3:
from elasticsearch import Elasticsearch
es = Elasticsearch(hosts=["localhost"])
timestamp_pipeline_setting = {
"description": "insert timestamp field for all documents",
"processors": [
{
"set": {
"field": "ingest_timestamp",
"value": "{{_ingest.timestamp}}"
}
}
]
}
es.ingest.put_pipeline("timestamp_pipeline", timestamp_pipeline_setting)
conf = {
"settings": {
"number_of_shards": 2,
"number_of_replicas": 1,
"default_pipeline": "timestamp_pipeline"
},
"mappings": {
"articles":{
"dynamic": "false",
"_source" : {"enabled" : "true" },
"properties": {
"title": {
"type": "text",
},
"content": {
"type": "text",
},
}
}
}
}
response = es.indices.create(
index="articles_index",
body=conf,
ignore=400 # ignore 400 already exists code
)
print ('\nresponse:', response)
doc = {
'title': 'automatically adding a timestamp to documents',
'content': 'prior to version 5 of Elasticsearch, documents had a metadata field called _timestamp. When enabled, this _timestamp was automatically added to every document. It would tell you the exact time a document had been indexed.',
}
res = es.index(index="articles_index", doc_type="articles", id=100001, body=doc)
print(res)
res = es.get(index="articles_index", doc_type="articles", id=100001)
print(res)
About ES 7.x, the example should work after removing the doc_type related parameters as it's not supported any more.
first create index and properties of the index , such as field and datatype and then insert the data using the rest API.
below is the way to create index with the field properties.execute the following in kibana console
`PUT /vfq-jenkins
{
"mappings": {
"properties": {
"BUILD_NUMBER": { "type" : "double"},
"BUILD_ID" : { "type" : "double" },
"JOB_NAME" : { "type" : "text" },
"JOB_STATUS" : { "type" : "keyword" },
"time" : { "type" : "date" }
}}}`
the next step is to insert the data into that index:
curl -u elastic:changeme -X POST http://elasticsearch:9200/vfq-jenkins/_doc/?pretty
-H Content-Type: application/json -d '{
"BUILD_NUMBER":"83","BUILD_ID":"83","JOB_NAME":"OMS_LOG_ANA","JOB_STATUS":"SUCCESS" ,
"time" : "2019-09-08'T'12:39:00" }'

Resources