What: I would like to know how to translate the messages for the micronaut-problem-json library. Does it support src/main/resources/i18n/messages.properties? This information is not documented on the GitHub project's page.
The project: https://github.com/micronaut-projects/micronaut-problem-json/
Why: The motivation for this is obvious, to support the internationalization of the messages.
This is a typical payload generated by the library in case of a constraint validation error:
{
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Constraint Violation",
"status": 400,
"violations": [
{
"field": "create.signup.username",
"message": "size must be between 3 and 30"
}
]
}
I would like to add support to other languages, like Portuguese, Spanish, etc. When an HTTP request from the client includes the HTTP header Accept-Language: pt the server should return the following payload:
{
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Violação de integridade",
"status": 400,
"violations": [
{
"field": "create.signup.username",
"message": "o tamanho deve ser entre 3 e 30"
}
]
}
Out of the box, neither micronaut-problem-json nor the problem library uses Java Internationalization.
There are customizations that you can do within Micronaut. See Micronaut Problem Json User Documentation.
You can always request the feature or provide a pull-request.
Related
I'm using Firebase Admin SDK Java API v6.12.2.
I call FirebaseAuth.getInstance().generatePasswordResetLink(email, actionCodeSettings) to generate a password reset link for users. If the email isn't registered, I get a big blob of text with embedded JSON from e.getMessage().
The looked at the FirebaseAuthException doc and it only exposes one method e.getErrorCode(), which in this case returns internal-error.
I can certainly parse this text to look for "EMAIL_NOT_FOUND" and translate it into a user-friendly message. But isn't that a very clumsy error message? At least, there should have been methods to return the error code 400, and a simple String message, and the details could go into a JSON object.
What is the recommended approach here by the Firebase team and how are other developers handling it?
Output of e.getMessage():
Unexpected HTTP response with status: 400; body: {
"error": {
"code": 400,
"message": "EMAIL_NOT_FOUND",
"errors": [
{
"message": "EMAIL_NOT_FOUND",
"domain": "global",
"reason": "invalid"
}
]
}
}
We used Spring Cloud Config version 2.1 and it worked.
We updated to Spring Cloud Config 2.2, and now it does not work.
More details are
https://github.com/spring-cloud/spring-cloud-config/issues/1599
I reported the issue to accelerate the process as well, or maybe it is not an issue. I do not know, so I am asking you to help.
Our config file: python-service.yml
resources:
- resource1
- resource2
newResources: []
As I learned, Spring Cloud config client makes requests to fetch configuration, and it passes header
Accept: application/vnd.spring-cloud.config-server.v2+json.
In Spring Cloud config v 2.1
Note, Spring Cloud version 2.1 does not send such header; instead, it sends Accept: application/json
HTTP http://localhost:8888/python-service/dev
Accept: application/vnd.spring-cloud.config-server.v2+json
Returns
{
"name": "python-service",
"profiles": [
"dev"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "file:/configuration/python-service.yml",
"source": {
"resources[0]": "resource1",
"resources[1]": "resource2",
"newResources": []
}
}
]
}
However, it Spring Cloud Config v 2.2, it fails
{
"timestamp": "2020-04-24T08:38:19.803+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException",
"path": "/python-service/dev"
}
The funny thing is that there is no exception log output in config-service logs!
If I remove the accept header, I will get (version 2.2)
{
"name": "python-service",
"profiles": [
"dev"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "file:/configuration/python-service.yml",
"source": {
"resources[0]": "resource1",
"resources[1]": "resource2",
"newResources": ""
}
}
]
}
Here, why "newResources": "" became an empty String, if it is expected to be an empty array - another question.
To sum up
1) How to use empty array in Spring Cloud config.
2) Why there is no log message about the NPE in Spring config-service logs.
3) Without the accept header, why "newResources": "" became an empty String, if I expected an empty array.
As for now, I can remove empty array from my config, but it is very scary because our config is used in many services! This breaks backward compatibility.
It turns out, it is a bug in Spring Boot.
https://github.com/spring-cloud/spring-cloud-config/issues/1572#issuecomment-620496235
https://github.com/spring-projects/spring-boot/issues/20506
Possible options:
1) Wait until it is fixed and update libraries.
2) What we did. We replaced empty array with empty element.
newResources:
anotherField: value
alternatively, use null. However, make sure, your code can handle it. Also, emptyArray can be treated as an emptyString. I found this out in debugger.
I have developed 4 apis using spring boot. Now i m trying to enable aws lambda for serverless. Is it possible to expose 4 api’s with single lambda.
Is it possible to expose 4 api’s with single lambda.
AWS lambda is FaaS - functions as a service, One function per Lambda.
However you can arguably achieve the intended functionality with a wrapper/proxy function as the entry point and route the request to upstream methods/functions as needed
Its described here aws api gateway & lambda: multiple endpoint/functions vs single endpoint
Take a look at the following documentation on creating an API Gateway => Lambda proxy integration:
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html
The following is merely a reworded explanation of what's given here aws api gateway & lambda: multiple endpoint/functions vs single endpoint .
AWS example has a good explanation; A Lambda request like the following:
POST /testStage/hello/world?name=me HTTP/1.1
Host: gy415nuibc.execute-api.us-east-1.amazonaws.com
Content-Type: application/json
headerName: headerValue
{
"a": 1
}
Will end up sending the following event data to your AWS Lambda function:
{
"message": "Hello me!",
"input": {
"resource": "/{proxy+}",
"path": "/hello/world",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"cache-control": "no-cache",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Content-Type": "application/json",
"headerName": "headerValue",
"Host": "gy415nuibc.execute-api.us-east-1.amazonaws.com",
"Postman-Token": "9f583ef0-ed83-4a38-aef3-eb9ce3f7a57f",
"User-Agent": "PostmanRuntime/2.4.5",
"Via": "1.1 d98420743a69852491bbdea73f7680bd.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "pn-PWIJc6thYnZm5P0NMgOUglL1DYtl0gdeJky8tqsg8iS_sgsKD1A==",
"X-Forwarded-For": "54.240.196.186, 54.182.214.83",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": {
"name": "me"
},
"pathParameters": {
"proxy": "hello/world"
},
"stageVariables": {
"stageVariableName": "stageVariableValue"
},
"requestContext": {
"accountId": "12345678912",
"resourceId": "roq9wj",
"stage": "testStage",
"requestId": "deef4878-7910-11e6-8f14-25afc3e9ae33",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": null,
"sourceIp": "192.168.196.186",
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "PostmanRuntime/2.4.5",
"user": null
},
"resourcePath": "/{proxy+}",
"httpMethod": "POST",
"apiId": "gy415nuibc"
},
"body": "{\r\n\t\"a\": 1\r\n}",
"isBase64Encoded": false
}
}
Now you have access to all headers, url params, body etc. So you could use that to handle requests differently in your wrapper/proxy Lambda function and route to upstream functions as per your routing needs.
Many people are using this methodology today as opposed to creating lambda function for each method and an api gateway resource.
There are pros and Cons to this approach
Deployment: if each lambda function is discrete then you can deploy them independently, which might reduce the risk from code changes (microservices strategy). Conversely you may find that needing to deploy functions separately adds complexity and is burdensome.
Self Description: API Gateway's interface makes it extremely intuitive to see the layout of your RESTful endpoints -- the nouns and verbs are all visible at a glance. Implementing your own routing could come at the expense of this visibility.
Lambda sizing and limits: If you proxy all -- then you'll wind up needing to choose an instance size, timeout etc. that will accommodate all of your RESTful endpoints. If you create discrete functions then you can more carefully choose the memory footprint, timeout, deadletter behavior etc. that best meets the needs of the specific invocation.
More on Monolithic lambda vs Micro Lambda here : https://hackernoon.com/aws-lambda-should-you-have-few-monolithic-functions-or-many-single-purposed-functions-8c3872d4338f
i am trying to use google api explorer to first try to insert an object to google cloud storage.
the request looks like
POST https://www.googleapis.com/storage/v1/b/visionapibucket/o?key={YOUR_API_KEY}
{
"contentType": "image/jpeg",
"uploadType": "media",
"path": "/upload/storage/v1/b/visionapibucket/o"
}
but i see the error as
400 HTTP/2.0 400
- Show headers -
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required"
},
{
"domain": "global",
"reason": "wrongUrlForUpload",
"message": "Upload requests must include an uploadType URL parameter and a URL path beginning with /upload/",
"extendedHelp": "https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload"
}
],
"code": 400,
"message": "Required"
}
}
not sure what i am missing. please advise
Looks like a bug on the website. It doesn't seem like the explorer supports media.
The request it generated looks like:
POST https://www.googleapis.com/storage/v1/b/visionapibucket/o?key={YOUR_API_KEY}
But a proper upload request would look like:
POST https://www.googleapis.com/upload/storage/v1/b/visionapibucket/o?key={YOUR_API_KEY}&uploadType=media&name=myfile.jpeg
You'll also want to include a "Content-Type" header specifying that it's a JPEG image.
There's a guide on the various ways to upload objects using the JSON API here. The specific type you're looking for is like a simple upload.
I have to post json to api_url for login.
{
"username":"testre","password":"password"
}
When I use postman to check this api, it reply successful authentication like below.
{
"status": "success",
"code": 200,
"message": "username, password validated.",
"data": [
{
"password": "password",
"username": "testre"
}
],
"links": [
{
"rel": "self",
"link": "http://localhost:2222/pizza-shefu/api/v1.0/customers/login/"
},
{
"rel": "profile",
"link": "http://localhost:2222/pizza-shefu/api/v1.0/customers/testre"
}
]
}
For an unauthorized json like below.
{
"status": "unauthorized",
"code": 401,
"errorMessage": "HTTP_UNAUTHORIZED",
"description": "credentials provided are not authorized."
}
Previously I code to retrieve it using java. But now I want to refactor it using RestTemplate in spring. The problem is every example I read is written for fixed number of variables https://spring.io/guides/gs/consuming-rest/. Here I get different numbers of variable according to the login success status. I am new to spring so I'm confused in creating the class for login reply which we get from rest template. (Such as this in the example Quote quote = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class); But I need to return a json object). I couldn't figure out how to write the RestTemplate part.
As suggested by #Andreas:
Add the superset of all fields for all possible responses
Identify the set of fields that are mandatory for every response and make them required
Make the rest of the fields as optional
Upon receveiving a response, check the status code and implement your logic accordingly.
If you are using Jackson for Deserialization, all fields are optional by default (see this question)