I want my client to be able to request metadata about a #RequestMapping, like the #Size and #Length values of each field. Does Spring have a way of doing this?
Closest thing might be Spring HATEOAS Affordances for HAL forms.
Spring HATEOAS Affordances
Responses produce output which includes all the metadata about the request model along with validation rules and method.
{
"_embedded": {
"employees": [...]
},
"_links": {
"self": {
"href": "http://localhost:8080/employees"
}
},
"_templates": {
"default": {
"title": null,
"method": "post",
"contentType": "",
"properties":[
{
"name": "firstName",
"required": true
},
{
"name": "id",
"required": true
},
{
"name": "lastName",
"required": true
},
{
"name": "role",
"required": true
}
]
}
}
}
Related
We have implemented swagger using OpenAPI 3.
We have a requirement where the external request will be sent with a path "{host}/v1/names" which will then be interpreted at gateway level and forwarded as "{host}/api/v1/names" to the deployed springboot application
In the springboot application we are using rest controller with
#RequestMapping(value="/api/v1/names")
So, when OpenApi Json is generated to be used in swagger, it defines path as "/api/v1/names". However, since external customer would use "/v1/names" to access the API, we want to show "/v1/names" in swagger and OpenApi json
Current JSON looks like this:
{
"openapi": "3.0.1",
"info": {
"title": "External API",
"description": "This set of API is used to serve external clients",
"version": "0.1"
},
"servers": [
{
"url": "https://api.xyz.net/",
"description": "Live"
}
],
"paths": {
"/api/v1/names": {
"get": {
"summary": ".",
"operationId": "getNames",
"parameters": [
{
"name": "pageable",
"in": "query",
"required": true,
"schema": {
"$ref": "#/components/schemas/Pageable"
}
}
],
"responses": {
"200": {
"description": "List of names",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/Pageable response"
}
}
}
}
}
}
}
}
}
Expected JSON (Different "path" value):
{
"openapi": "3.0.1",
"info": {
"title": "External API",
"description": "This set of API is used to serve external clients",
"version": "0.1"
},
"servers": [
{
"url": "https://api.xyz.net/",
"description": "Live"
}
],
"paths": {
"/v1/names": {
"get": {
"summary": ".",
"operationId": "getNames",
"parameters": [
{
"name": "pageable",
"in": "query",
"required": true,
"schema": {
"$ref": "#/components/schemas/Pageable"
}
}
],
"responses": {
"200": {
"description": "List of names",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/Pageable response"
}
}
}
}
}
}
}
}
}
I have been trying to figure out any way to do this through some configuration or annotation, but not found anything yet.
Thanks in advance for your suggestions and help.
I'm constructing a message to be sent through my spring boot application.
I was testing out the templates and I have created one where most of the elements are static except a link that needs to be generated by the code and added to the Json.
Currently the Json message looks like this:
{
"blocks": [
{
"type": "context",
"elements": [
{
"type": "image",
"image_url": "https://api.slack.com/img/blocks/bkb_template_images/highpriority.png",
"alt_text": "High Priority"
},
{
"type": "mrkdwn",
"text": "*High Priority*"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Hercules Platform Status Response failed Messages*"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Please click the link to download the file*"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<LINK|SOME_LINK>*"
}
}
]
}
I'm not sure how to construct this Json in my spring boot application. Since most of it is static, should I just load this template as a string and append the last link section?
I'm not able to figure out the slack classes in java to build such a message.
{
"status": 200,
"id": "123e4567-e89b-12d3-a456-426655440000",
"shop": {
"c73bcdcc-2669-4bf6-81d3-e4ae73fb11fd": {
"123e4567-e89b-12d3-a456-426655443210": {
"quantity": {
"value": 10
}
},
"123e4567-e89b-12d3-a456-426655443211": {
"quantity": {
"value": 20
}
}
}
}
}
This is my json response. I want to validate the fields "c73bcdcc-2669-4bf6-81d3-e4ae73fb11fd" , "123e4567-e89b-12d3-a456-426655443210" and "123e4567-e89b-12d3-a456-426655443211", which are uniquely generated every time whenever hits the endpoint.
Building on #pxcv7r's answer:
To validate UUID in particular, you may use format in JSON schema, which provides built-in support for the UUID syntax: { "type": "string", "format": "uuid" }
See https://json-schema.org/understanding-json-schema/reference/string.html
Additionally, you can use a combination of "propertyNames" and "unevaluatedProperties" to avoid the need for any regular expression:
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"id": {
"type": "string",
"format": "uuid"
},
"shop": {
"type": "object",
"minProperties": 1,
"maxProperties": 1,
"propertyNames": {
"format": "uuid"
},
"unevaluatedProperties": {
"type":"object",
"minProperties": 1,
"propertyNames": {
"format": "uuid"
},
"unevaluatedProperties": {
"title": "single variant of a shop",
"type": "object",
"properties": {
"quantity": {
"type": "object",
"properties": {
"value": {
"type": "integer"
}
}
}
}
}
}
}
}
}
To validate in JSON schema that a string conforms to a regular expression pattern use
{ "type": "string", "pattern": "\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b" }
The concrete pattern is adapted from the question Searching for UUIDs in text with regex see there for more details.
To validate UUID in particular, you may use format in JSON schema, which provides built-in support for the UUID syntax: { "type": "string", "format": "uuid" }
See https://json-schema.org/understanding-json-schema/reference/string.html
You need "patternProperties":
{
"$schema":"http://json-schema.org/draft-07/schema#",
"type":"object",
"properties": {
"shop":{
"type":"object",
"additionalProperties":false,
"patternProperties":{
"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}": {
"type":"object",
"patternProperties" :{
"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}":{
"type":"object",
"properties":{
"quantity":{
"type":"object",
"properties":{
"value":{
"type":"integer"
}
}
}
}
}
}
}
}
}
}
}
How to create n number of instances in GCP using rest api.
in AWS java SDK, there is a method withMaxCount where we specify number of ec2 instances.
Similarly is there anything for GCP compute.
You can use REST API in loop to create instances.
Example request will look something like this:
{
"kind": "compute#instance",
"name": "INSTANCE-NAME",
"zone": "projects/PROJECT-NAME/zones/us-central1-a",
"machineType": "projects/PROJECT-NAME/zones/us-central1-a/machineTypes/e2-medium",
"displayDevice": {
"enableDisplay": false
},
"metadata": {
"kind": "compute#metadata",
"items": []
},
"tags": {
"items": []
},
"disks": [
{
"kind": "compute#attachedDisk",
"type": "PERSISTENT",
"boot": true,
"mode": "READ_WRITE",
"autoDelete": true,
"deviceName": "INSTANCE-NAME",
"initializeParams": {
"sourceImage": "projects/debian-cloud/global/images/debian-10-buster-v20210122",
"diskType": "projects/PROJECT-NAME/zones/us-central1-a/diskTypes/pd-standard",
"diskSizeGb": "10",
"labels": {}
},
"diskEncryptionKey": {}
}
],
"canIpForward": false,
"networkInterfaces": [
{
"kind": "compute#networkInterface",
"subnetwork": "regions/us-central1/subnetworks/default",
"accessConfigs": [
{
"kind": "compute#accessConfig",
"name": "External NAT",
"type": "ONE_TO_ONE_NAT",
"networkTier": "PREMIUM"
}
],
"aliasIpRanges": []
}
],
"description": "",
"labels": {},
"scheduling": {
"preemptible": false,
"onHostMaintenance": "MIGRATE",
"automaticRestart": true,
"nodeAffinities": []
},
"deletionProtection": false,
"reservationAffinity": {
"consumeReservationType": "ANY_RESERVATION"
},
"serviceAccounts": [
{
"email": "111111111111-compute#developer.gserviceaccount.com",
"scopes": [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"shieldedInstanceConfig": {
"enableSecureBoot": false,
"enableVtpm": true,
"enableIntegrityMonitoring": true
},
"confidentialInstanceConfig": {
"enableConfidentialCompute": false
}
}
Replace it with your own project name and service account, and you can test it here.
I have a complex index with a ngram analyzer. I want to be able to create a new index through the Java API. I am currently using Kotlin for this but using the same framework. I have created the schema for this index as so:
{
"settings": {
"index": {
"max_ngram_diff": 20,
"search.idle.after": "10m"
},
"analysis": {
"analyzer": {
"ngram3_analyzer": {
"tokenizer": "ngram3_tokenizer",
"filter": [
"lowercase"
]
}
},
"tokenizer": {
"ngram3_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 20
}
}
}
},
"mappings": {
"dynamic": "strict",
"_doc": {
"properties": {
"name": {
"type": "keyword",
"fields": {
"partial": {
"type": "text",
"analyzer": "ngram3_analyzer",
"search_analyzer": "keyword"
},
"text": {
"type": "text"
}
}
},
"location": {
"type": "geo_shape",
"ignore_malformed": true
},
"type": {
"type": "keyword"
},
"sort": {
"type": "integer"
}
}
}
}
}
This json schema works when manually passing it via a rest client PUT call.
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "new_index_created"
}
Passing the same schema via elastic java API using the following koltin function:
private fun createIndex(index: String, schema: String) {
val createIndexRequest = CreateIndexRequest(index).mapping(schema, XContentType.JSON)
getClient().indices().create(createIndexRequest, RequestOptions.DEFAULT)
}
I get this response:
Elasticsearch exception [type=mapper_parsing_exception, reason=Failed to parse mapping [_doc]: Root mapping definition has unsupported parameters: [settings : {index={max_ngram_diff=20, search.idle.after=10m}, analysis={analyzer={ngram3_analyzer={filter=[lowercase], tokenizer=ngram3_tokenizer}}, tokenizer={ngram3_tokenizer={min_gram=3, type=ngram, max_gram=20}}}}] [mappings : {_doc={properties={name={type=keyword, fields={text={type=text}, partial={search_analyzer=keyword, analyzer=ngram3_analyzer, type=text}}}, location={ignore_malformed=true, type=geo_shape}, sort={type=integer}, type={type=keyword}}}, dynamic=strict}]]
any help on this issue would be great :)
The error you get is because you're passing both mappings and settings into the mapping(...) call.
You can either call mapping() with only the mappings section and setting() with the settings section, or you can call source() like this:
val createIndexRequest = CreateIndexRequest(index).source(schema, XContentType.JSON)
^
|
change this