SlideShare a Scribd company logo
@asbjornu
GET /presentation HTTP/1.1

HTTP/1.1 400 Bad Request

Content-Type: application/problem+json
{

"title": "What’s Your Problem?",

"detail": "Nordic APIs 2019 Platform Summit",

"date": "2019-10-24T13:20+02:00"

"status": 400,

}
@asbjornu
Asbjørn Ulsberg
Developer Experience Architect
@asbjornu
<errors are="hard">
@asbjornu
Michael Timbs 01:14
I’ve just been pulled in to fix some flask middleware that
sits between two APIs and all the errors return 200 OK.
The messages are also random and often overwritten
multiple times before being returned.
@asbjornu
Ethan 03:42

One API I integrated with, when it was overloaded
would give a response meaning "try again later",
consisting of a 200 with a completely empty body.
@asbjornu
Pieter Herroelen 09:30
A customer was complaining about 500 Internal
Server Errors. So they changed the catch-all error
status code to 400.
@asbjornu
Matt Bishop 17:32
Historically, Flash would only pass 200 responses back
to application code so we would have to use an error
object instead of status codes.
@asbjornu
@Hvattum
Got a database schema dump in the stacktrace from a server not that
long ago. It was unexpectedly helpful in understanding what went
wrong, and where server validation failed.
11:42 AM · Aug 27, 2019 · Twitter Web App
@asbjornu
@DesignerAndGeek
Yes. Here is a comment from my source code:
// Stupidly, the API reports success == false if no result.
// Therefore, no success but no errors = not really an error.


6:53 AM · Aug 27, 2019 · Twitter Web App
@asbjornu
@cjno
I once worked with an API that basically reimplemented HTTP in JSON:
always 200 OK, body included `status` (200-5XX), `headers`(!) and `body`
6:22 AM · Aug 27, 2019 · Twitter Web App
@thomanil
Same here, different company
7:12 AM · Aug 27, 2019 · Twitter Web App
@bjartnes
It's more like raise your hand if you haven't seen one :-D. I think I was
part of building one as well. Or two. Don't know. My brain is good at
suppressing such things.
7:28 AM · Aug 27, 2019 · Twitter Web App
@asbjornu
@launchany
Unix devs returning 0 on success, 1-127 for errors
3:19 AM · Aug 27, 2019 · Twitter for iPad
@asbjornu
</errors>
@asbjornu
<categorizing what="errors">
@asbjornu
Client API Service
4xx 5xx
@asbjornu
Service
5xx
Client
4xx
?
API
@asbjornu
Core
Controller
Service
Client
Mapping
Mapping
Validation
4xx 5xx
@asbjornu
CustomerResponse CreateCustomer(CustomerRequest customerRequest)
{
customerRequest.Validate();
var customer = customerRequest.Map();
customer = this.customerRepository.Add(customer);
var customerResponse = new CustomerResponse(customer);
return customerResponse;
}
4xx
5xx
@asbjornu
</categorizing>
@asbjornu
<map from="exception" to="http">
@asbjornu
Core
@asbjornu
Infrastructure
Core
API Daemon
Web UI
@asbjornu
Infrastructure
Core
API Daemon
Web UI
@asbjornu
Infrastructure
throw;
API Daemon
Web UI
@asbjornu
Infrastructure
catch; catch;
catch;
throw;
@asbjornu
CustomerResponse CreateCustomer(CustomerRequest customerRequest)
{
customerRequest.Validate();
var customer = customerRequest.Map();
customer = this.customerRepository.Add(customer);
var customerResponse = new CustomerResponse(customer);
return customerResponse;
}
@asbjornu
CustomerResponse CreateCustomer(CustomerRequest customerRequest)
{
customerRequest.Validate();
var customer = customerRequest.Map();
customer = this.customerRepository.Add(customer);
var customerResponse = new CustomerResponse(customer);
return customerResponse;
}
@asbjornu
class CustomerRequest
{
public void Validate()
{
try
{
// Perform validation
}
catch (Exception validationException)
{
throw new RequestException(exception);
}
}
}
@asbjornu
class CustomerRequest
{
public void Validate()
{
try
{
// Perform validation
}
catch (Exception validationException)
{
throw new RequestException(exception);
}
}
}
@asbjornu
throw ✔
catch ?
@asbjornu
class ExceptionHandler
{
public HttpResponse Handle(Exception exception)
{
}
}
@asbjornu
class ExceptionHandler
{
public HttpResponse Handle(Exception exception)
{
var problem = new Problem(exception);
return problem.CreateResponse();
}
}
Problem
• RFC 7807: Problem Details for HTTP APIs

• application/problem+json
• Standard format for errors

• Don’t reinvent the wheel

• Unless your business is producing error description formats
Problem
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
@asbjornu
class ExceptionHandler
{
public HttpResponse Handle(Exception exception)
{
var problem = new Problem(exception);
return problem.CreateResponse();
}
}
class Problem
{
public Problem(Exception exception)
{
Type = new Uri("https://example.com/errors/server-error");
Status = 500;
Title = "An unexpected error occurred.";
if (exception is RequestException)
{
Type = new Uri("https://example.com/errors/bad-request");
Status = 400;
Title = exception.Title;
}
}
public Uri Type { get; }
public int Status { get; }
public string Title { get; }
}
class Problem
{
public HttpResponse CreateResponse()
{
return new HttpResponse
{
ContentType = "application/problem+json",
Body = JsonConvert.FromObject(new
{
type = Type,
status = Status
title = Title
})
}
}
public Uri Type { get; }
public int Status { get; }
public string Title { get; }
}
Status
@asbjornu
417 Expectation Failed
400 Bad Request
401 Unauthorized
428 Precondition Required
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Payload Too Large
414 URI Too Long
415 Unsupported Media Type
403 Forbidden
GET /presentation HTTP/1.1

Accept: spongebob/squarepants
406NotAcceptable
HTTP/1.1 406 Not Acceptable

Content-Type: application/problem+json
{
"status": 406,
"type": "https://example.com/probs/not-acceptable",
"title": "Not Acceptable",
"detail": "spongebob/squarepants is not an

acceptable content-type.",
}
406NotAcceptable GET /presentation HTTP/1.1

Accept: spongebob/squarepants
GET /presentation HTTP/1.1

Expect: 99-air-balloons
417ExpectationFailed
HTTP/1.1 417 Expectation Failed

Content-Type: application/problem+json
{
"status": 417,
"type": "https://example.com/probs/expect-fail",
"title": "Expectation Failed",
"detail": "99-air-balloons is an outrageous
expectation",
}
417ExpectationFailed GET /presentation HTTP/1.1

Expect: 99-air-balloons
428PreconditionRequired PUT /presentation HTTP/1.1


{
"lostUpdate": true
}
HTTP/1.1 428 Precondition Required

Content-Type: application/problem+json
{
"status": 428,
"type": "https://example.com/probs/precond-fail",
"title": "Precondition Required",
"detail": "Missing If-Match header in the request.",
}
428PreconditionRequired PUT /presentation HTTP/1.1


{
"lostUpdate": true
}
@asbjornu
</map>
@asbjornu
<map from="http" to="exception">
@asbjornu
Request Response Status?
2xx
3xx
Present
Redirect
4xx RequestException
5xx ServerException
@asbjornu
4xx 4xx?
400 BadRequestException
401 UnauthorizedException
404 NotFoundException
428 PreconditionFailedException
@asbjornu
class RequestException : Exception
class BadRequestException : RequestException
class UnauthorizedException : RequestException
class PreconditionFailedException : RequestException
class NotFoundException : RequestException
@asbjornu
class RequestException : Exception
class BadRequestException : RequestException
class UnauthorizedException : RequestException
class PreconditionFailedException : RequestException
class NotFoundException : RequestException
@asbjornu
class RequestException : Exception
class BadRequestException : RequestException
class UnauthorizedException : RequestException
class PreconditionFailedException : RequestException
class NotFoundException : RequestException
@asbjornu
class RequestException : Exception
class BadRequestException : RequestException
class UnauthorizedException : RequestException
class PreconditionFailedException : RequestException
class NotFoundException : RequestException
@asbjornu
class RequestException : Exception
class BadRequestException : RequestException
class UnauthorizedException : RequestException
class PreconditionFailedException : RequestException
class NotFoundException : RequestException
@asbjornu
class ServerException : Exception
class InternalServerException : ServerException
class BadGatewayException : ServerException
class GatewayTimeoutException : ServerException
class ServiceUnavailableException : ServerException
@asbjornu
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
@asbjornu
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}
@asbjornu
HTTP/1.1 403 Forbidden

Content-Type: application/problem+json
{
"status": 403,
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"problems": [{
"name": "amount",
"description": "The amount is too high"
}]
}


You do not have enough credit.
Your current balance is 30, but that costs 50.
The amount is too high
What’s Your Problem?
@asbjornu
</map>
@asbjornu
<summary>
@asbjornu
Error messages
initiate a dialogue
with the receiver
@asbjornu
Make the dialogue
constructive
@asbjornu
Enable the receiver
to be self-serviced
@asbjornu
throw Exceptions in
the Core
@asbjornu
Use existing
Exceptions if
available
@asbjornu
Create your own
Exceptions when
needed
@asbjornu
Add context to the
Exceptions you
throw
@asbjornu
Translate Exceptions
into problem+json at
the latest possible
moment
@asbjornu
Translate
problem+json into
Exceptions and throw
@asbjornu
</summary>
@asbjornu
Onion Architecture
Domain-driven design
Ports and Adapters
j.mp/ddd-es-cqrs
slack.httpapis.com
REST
Clean Code
@asbjornu
<thank who="you" />

More Related Content

PDF
What's Your Problem?
PDF
- Webexpo 2010
PDF
Pushing the Web: Interesting things to Know
PPTX
สปริงเฟรมเวิร์ค4.1
PDF
Ams adapters
PDF
Resources and relationships at front-end
PDF
Enter the app era with ruby on rails
PDF
Frontends w ithout javascript
What's Your Problem?
- Webexpo 2010
Pushing the Web: Interesting things to Know
สปริงเฟรมเวิร์ค4.1
Ams adapters
Resources and relationships at front-end
Enter the app era with ruby on rails
Frontends w ithout javascript

What's hot (10)

PDF
GraphQL - when REST API is to less - lessons learned
PDF
Micro app-framework
PDF
Intro to computer vision in .net update
PPTX
How to Leverage APIs for SEO #TTTLive2019
PDF
Angularjs
PDF
Angularjs
PDF
Angular js book
PPTX
REST API Design for JAX-RS And Jersey
PPTX
Elegant Rest Design Webinar
PPTX
Bare-knuckle web development
GraphQL - when REST API is to less - lessons learned
Micro app-framework
Intro to computer vision in .net update
How to Leverage APIs for SEO #TTTLive2019
Angularjs
Angularjs
Angular js book
REST API Design for JAX-RS And Jersey
Elegant Rest Design Webinar
Bare-knuckle web development
Ad

Similar to What’s Your Problem? (20)

PPTX
Android and REST
PDF
Servlets http-status-codes
PDF
The never-ending REST API design debate
PDF
The never-ending REST API design debate -- Devoxx France 2016
PDF
Symfony without the framework
PDF
APIs - the good, the bad & the ugly
PDF
Great webapis
PPTX
Http Status Message - Pocket Guide
PPTX
HTTP Status Codes you should know and use while building APIs
PDF
Restful api design
PDF
Defense by numbers: Making Problems for Script Kiddies and Scanner Monkeys
PPTX
BITM3730Week9(1).pptx
PDF
Создание API, которое полюбят разработчики. Глубокое погружение
PDF
REST 101: An Overview To Representational State Transfer.
ODP
NEPHP '13: Pragmatic API Development
PPTX
FHIR REST API
PPTX
API Pain Points (PHPNE)
PDF
RefCard RESTful API Design
PDF
Design Web Service API by HungerStation
PDF
APIs REST Usables con Hypermedia por Javier Ramirez, para codemotion
Android and REST
Servlets http-status-codes
The never-ending REST API design debate
The never-ending REST API design debate -- Devoxx France 2016
Symfony without the framework
APIs - the good, the bad & the ugly
Great webapis
Http Status Message - Pocket Guide
HTTP Status Codes you should know and use while building APIs
Restful api design
Defense by numbers: Making Problems for Script Kiddies and Scanner Monkeys
BITM3730Week9(1).pptx
Создание API, которое полюбят разработчики. Глубокое погружение
REST 101: An Overview To Representational State Transfer.
NEPHP '13: Pragmatic API Development
FHIR REST API
API Pain Points (PHPNE)
RefCard RESTful API Design
Design Web Service API by HungerStation
APIs REST Usables con Hypermedia por Javier Ramirez, para codemotion
Ad

More from Nordic APIs (20)

PPTX
How to Choose the Right API Platform - We Have the Tool You Need! - Mikkel Iv...
PPTX
Bulletproof Backend Architecture: Building Adaptive Services with Self-Descri...
PDF
Implementing Zero Trust Security in API Gateway with Cilium - Pubudu Gunatila...
PPTX
Event-Driven Architecture the Cloud-Native Way - Manuel Ottlik, HDI Global SE
PPTX
Navigating the Post-OpenAPI Era with Innovative API Design Frameworks - Danie...
PDF
Using Typespec for Open Finance Standards - Chris Wood, Ozone API
PPTX
Schema-first API Design Using Typespec - Cailin Smith, Microsoft
PPTX
Avoiding APIpocalypse; API Resiliency Testing FTW! - Naresh Jain, Xnsio
PPTX
How to Build an Integration Platform with Open Source - Magnus Hedner, Benify
PPTX
API Design First in Practise – An Experience Report - Hari Krishnan, Specmatic
PPTX
The Right Kind of API – How To Choose Appropriate API Protocols and Data Form...
PPTX
Why Frequent API Hackathons Are Key to Product Market Feedback and Go-to-Mark...
PPTX
Maximizing API Management Efficiency: The Power of Shifting Down with APIOps ...
PPTX
APIs Vs Events - Bala Bairapaka, Sandvik AB
PPTX
GraphQL in the Post-Hype Era - Daniel Hervas, Reckon Digital
PPTX
From Good API Design to Secure Design - Axel Grosse, 42Crunch
PPTX
API Revolution in IoT: How Platform Engineering Streamlines API Development -...
PPTX
Unlocking the ROI of API Platforms: What Success Actually Looks Like - Budhad...
PDF
Increase Your Productivity with No-Code GraphQL Mocking - Hugo Guerrero, Red Hat
PPTX
Securely Boosting Any Product with Generative AI APIs - Ruben Sitbon, Theodo ...
How to Choose the Right API Platform - We Have the Tool You Need! - Mikkel Iv...
Bulletproof Backend Architecture: Building Adaptive Services with Self-Descri...
Implementing Zero Trust Security in API Gateway with Cilium - Pubudu Gunatila...
Event-Driven Architecture the Cloud-Native Way - Manuel Ottlik, HDI Global SE
Navigating the Post-OpenAPI Era with Innovative API Design Frameworks - Danie...
Using Typespec for Open Finance Standards - Chris Wood, Ozone API
Schema-first API Design Using Typespec - Cailin Smith, Microsoft
Avoiding APIpocalypse; API Resiliency Testing FTW! - Naresh Jain, Xnsio
How to Build an Integration Platform with Open Source - Magnus Hedner, Benify
API Design First in Practise – An Experience Report - Hari Krishnan, Specmatic
The Right Kind of API – How To Choose Appropriate API Protocols and Data Form...
Why Frequent API Hackathons Are Key to Product Market Feedback and Go-to-Mark...
Maximizing API Management Efficiency: The Power of Shifting Down with APIOps ...
APIs Vs Events - Bala Bairapaka, Sandvik AB
GraphQL in the Post-Hype Era - Daniel Hervas, Reckon Digital
From Good API Design to Secure Design - Axel Grosse, 42Crunch
API Revolution in IoT: How Platform Engineering Streamlines API Development -...
Unlocking the ROI of API Platforms: What Success Actually Looks Like - Budhad...
Increase Your Productivity with No-Code GraphQL Mocking - Hugo Guerrero, Red Hat
Securely Boosting Any Product with Generative AI APIs - Ruben Sitbon, Theodo ...

Recently uploaded (20)

PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Electronic commerce courselecture one. Pdf
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Encapsulation theory and applications.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Spectral efficient network and resource selection model in 5G networks
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
Unlocking AI with Model Context Protocol (MCP)
Understanding_Digital_Forensics_Presentation.pptx
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Building Integrated photovoltaic BIPV_UPV.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
NewMind AI Weekly Chronicles - August'25 Week I
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
The Rise and Fall of 3GPP – Time for a Sabbatical?
Electronic commerce courselecture one. Pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Encapsulation theory and applications.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Dropbox Q2 2025 Financial Results & Investor Presentation
Spectral efficient network and resource selection model in 5G networks
The AUB Centre for AI in Media Proposal.docx
NewMind AI Monthly Chronicles - July 2025
Unlocking AI with Model Context Protocol (MCP)

What’s Your Problem?